草庐IT

关于 javascript:map() 与 async 与 promise.all()

codeneng 2023-03-28 原文

map() with async vs promise.all()

如果我有一个元素数组并且我想对它们进行并行操作。
我会使用 promise.all()

我知道 promise.all() 接受一系列Promise。如果我错了,请纠正我,我不这么认为。
在这里,它清楚地表明。

The Promise.all() method returns a single Promise that fulfills when all of the promises passed as an iterable have been fulfilled or when the iterable contains no promises or when the iterable contains promises that have been fulfilled and non-promises that have been returned. It rejects with the reason of the first promise that rejects, or with the error caught by the first argument if that argument has caught an error inside it using try/catch/throw blocks.

所以,是的,我们可以将简单的函数传递给 promise.all(),如果它们返回则解析,如果抛出错误则拒绝。
现在看看下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const promises = todayAssignedJobs.map(async todayAssigned => {
  const [leaderboard, created] = await Leaderboard.findOrCreate({...});

  if (!created) {
    const rating = (todayAssigned.rating + leaderboard.rating * leaderboard.jobs_completed) / (leaderboard.jobs_completed + 1);
    const commission = todayAssigned.commission + leaderboard.commission;
    const jobsCompleted = leaderboard.jobs_completed + 1;

    await Leaderboard.update({
      rating,
      commission,
      jobs_completed: jobsCompleted,
      updated_by: 'system',
    }, {
      where: {
        id: leaderboard.id,
      },
    });
  }

  await AssignedJob.update({
    is_leaderboard_generated: true,
  }, {
    where: {
      id: todayAssigned.id,
    },
  });
});

await Promise.all(promises);

在这里,我有一个疑问。
我们正在迭代数组的每个元素并对它们进行异步操作。他们没有明确返回任何东西。
所以,我认为 map 也在这里做并行操作。
为什么要在这里使用 promise.all() 呢?

  • 为什么要在这里使用 promise.all() 呢?相对于..?您是否正在考虑使用 for 循环?
  • 一点也不,如果 map() 异步执行。为什么我们两者都需要? map() 是否在这里等待第一个异步操作完成?在这种情况下,promise.all() 做了什么?
  • "他们没有明确返回任何东西"?? async 函数根据定义返回一个 Promise
  • 在所有映射的异步函数完成后,您是否需要执行任何操作?如果是这样,这就是您需要 Promise.all() 的目的。如果没有,那么你可以不用它,你的映射函数将做他们必须做的事情,而不会中断外面的代码
  • "如果 map() 异步执行" map 不会异步执行任何操作。
  • @Kaiido 我们正在对每个元素进行异步操作。它可能会等待完成(请在此处纠正我),但操作在这里是异步的。
  • "它可能会等待它完成"??如果"它"是指 .map(),那么不,它不会等待任何东西
  • @Phil如果它不等待,那么它正在并行地做事。对?
  • 正确,但下面有更好的信息??
  • 不,地图都是同步的。它会同步声明你的 Promise。使用 setTimeout 可能更容易掌握? [1,2,3,4].map( () => setTimeout( doSomething, 3000) ) 将同步返回 setTimeout() 的结果(超时 id),即使 doSomething 只会在 3 秒内被调用
  • @Phil 我在这里缺少的一条非常有用的信息是这个 async fun() { await some(); await another(); } 将在这里返回什么?
  • @SujeetAgrahari 一个 Promisesome()another() 完成时解析(没有值)
  • @Phil 知道了,fun() 将返回一个 Promise。当所有Promise都解决时,它将被解决,如果其中一个被拒绝,它将被拒绝?
  • @SujeetAgrahari 正确。相当于 return some().then(() => another()).then(() => {})


.map() 不是Promise感知的。所以,当你像你一样向它传递一个 async 回调时,它不会注意返回的Promise。因此,它只是一个接一个地运行循环,而不是等待任何返回的Promise。因此,在 .map() 循环中启动的所有异步操作将同时进行。

如果那是你想要的,并且你想收集所有返回的 Promise,以便以后可以看到它们何时都用 Promise.all() 完成,那么这个模式很好用:

1
Promise.all(someArray.map(callbackThatReturnsAPromiseHere))

而且,这是一种常见的设计模式。事实上,Bluebird Promise 库有一个特殊的函数将这两者结合起来,称为 Promise.map()。它还提供了另一个不错的功能,让您可以控制一次可以运行多少并发异步操作(因为它的 map() 操作是 promise-aware)。

听起来您正试图弄清楚是否应该只使用 .map() 而不使用 Promise.all()。如果这样做,您将并行运行异步操作,但您将不知道它们何时全部完成,也不知道有能力收集所有结果。您将在返回的Promise数组上使用 Promise.all() 以了解它们何时全部完成和/或收集它们的已解决结果。

仅供参考,.map() 只是一个普通的循环。它没有任何特殊的异步功能或任何特殊的并行运行功能。如果你愿意,你可以用 for 循环做同样的事情。它不会暂停您的 async 回调以等待它完成,因此运行它的副作用是您启动了一堆并行异步操作。

  • 我大吃一惊。至少我是对的,map 会并行触发它们。它不会等待他们的返回值,这一行很棒。我不知道。这就是为什么我应该做 promise.all() 以确保所有Promise都得到履行。 :)
  • 所以,基本上现在 promise.all() 将观察他们返回的Promise,如果他们得到解决,对吧?
  • @SujeetAgrahari - 是的, promise.all() 的全部目的是观察一系列Promise,并告诉您第一个Promise何时拒绝(并向您报告拒绝原因)或它们何时全部完成(并报告一系列已解决的值) 并且 .map() 不会为您执行此操作。 .map() 将为您收集 Promise 数组,就像它从回调中收集任何返回值并运行初始循环一样,但这就是它所做的一切。


如果你想在所有操作完成后做某事,你只需要Promise.all。例如:

1
2
3
4
5
6
7
8
const promises = todayAssignedJobs.map(async todayAssigned => {
  // lots of async stuff
});

await Promise.all(promises);

// now, all Promises have resolved
// alert the user that the leaderboard is completely updated

如果您在确定所有 Promise 都已完成后不需要发生任何事情,那么 Promise.all 就没有意义了 - 您也可以在循环中创建 Promise 并让他们保持原样。在这种情况下,由于您不会使用 Promise 的结果数组,因此使用 forEach (这是用于副作用的数组方法)会更合适。

不过有一个问题 - 你没有处理错误,但应该处理错误,否则它们会给出警告或退出 Node 进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const processJob = async (todayAssigned) => {
  const [leaderboard, created] = await Leaderboard.findOrCreate({...});

  if (!created) {
    // ...

// ...
todayAssignedJobs.forEach(async todayAssigned => {
  try {
    await processJob(todayAssigned);
  } catch(e) {
    // handle errors
  }
});

这里 Promise.all 的目的是能够在继续之前等待所有的Promise。

如果你在 await Promise.all(promises); 之前添加了一个console.log,它会在任何promise 解决之前同步运行,而console.log 紧随该行之后只会在所有promise 都解决之后才会出现。

有关关于 javascript:map() 与 async 与 promise.all()的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby-on-rails - ActiveRecord destroy_all - 2

    在Rails4.1中,ActiveRecorddestroy_all是否将整个函数包装在一个事务中?例如,如果我有一堆记录,我对其执行了destroy_all操作,它们对这些单独的对象运行了一些回调,其中一个失败了,整个操作会在那个时候回滚吗? 最佳答案 看起来不像:#Fileactiverecord/lib/active_record/relation.rb,line386defdestroy_all(conditions=nil)ifconditionswhere(conditions).destroy_allelseto_a.

  3. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  4. ruby - 在 ruby​​ 中使用 .try 函数和 .map 函数 - 2

    我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法

  5. ruby-on-rails - 关于 Ruby 的一般问题 - 2

    我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia

  6. ruby - 不能将 `each` 的所有或大多数情况替换为 `map` 吗? - 2

    Enumerable#each和Enumerable#map的区别在于返回的是接收者还是映射后的结果。回到接收者是微不足道的,你通常不需要在each之后继续一个方法链,比如each{...}.another_method(我可能没见过这样的案例。即使你想回到接收者那里,你也可以通过tap来实现)。所以我认为所有或者大部分使用Enumerable#each的情况都可以用Enumerable#map代替。我错了吗?如果我是对的,each的目的是什么?map是否比each慢?编辑:我知道当您对返回值不感兴趣时​​使用each是一种常见的做法。我对这种做法是否存在不感兴趣,但感兴趣的是,除了从

  7. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  8. ruby - caches_page :all - 2

    有什么方法可以告诉Rails3在给定的Controller中缓存所有页面,而不必在调用caches_page时列出所有页面?我尝试了caches_page:all,但它不起作用。 最佳答案 有点像实现的错误,但我刚刚尝试过它并且它适用于Rails3.0.6:caches_page:except=>[] 关于ruby-caches_page:all,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/que

  9. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

    我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

  10. ruby - 关于 Ruby 中 Dir[] 和 File.join() 的混淆 - 2

    我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案

随机推荐