JavaScript 中什么时候需要 async、await、promise.all?

When is async, await, promise.all needed in JavaScript?

我正在努力提高代码性能,经过多年的编码,我发现自己对一些基础知识感到困惑。 当然,我们基本上有需要按顺序进行的事情(异步函数)和并行的事情(只是同步的普通函数)。我阅读了 promise.all 和 setTimeout 类型的示例,并尝试用所有这些基础知识重写一个大函数,并在每个函数上都使用异步,当我完成时它比以前慢得多,现在我意识到异步是没有我想象的那么普遍,但我很困惑。

如果我有这个功能

function count(n){
  let num = 0
  for(let i = n; i--;){
    num++
  }
  return num
}

然后输入 140000000 这样需要一秒钟才能完成。如果我需要函数的其余部分的返回值才能继续,我想我需要等待响应,以便我可以继续使用响应

async function doSomething(){
  const one = await count(140000000)
  const two = count(one)
  return two
}
async function count(n){
  let num = 0
  for(let i = n; i--;){
    num++
  }
  return num
}

但事实上,我认为与其说是我需要传递给下一个函数才能工作的值,不如说它基本上没问题,无需等待响应,因为它基本上发送一个函数作为参数,如[=19] =]

async function doSomething(){
  const two = count(count(140000000))
  return two
}

function count(n){
  let num = 0
  for(let i = n; i--;){
    num++
  }
  return num
}

与同步类型的任务类似,我认为我需要使用 Promise.all 来加快并发 运行ning 函数的速度,并且它所采用的函数应该是异步的,因为它 returns像

这样的承诺
async function parent2(){
  console.log('start')
  console.time('ALL')
  const numsToCount = [ 140000000, 170000000, 240000000 ]
  const res = await countNums2(numsToCount)
  // do other stuff with res
  const fin = count(res[0])
  console.timeEnd('ALL')
  console.log('end', fin)
}

async function countNums2(numsToCount){
  let countedNumsPromises = []
  for(let i = numsToCount.length; i--;){
    countedNumsPromises.push(count2(numsToCount[i]))
  }
  return Promise.all(countedNumsPromises)
}

async function count2(n){
  let num = 0
  for(let i = n; i--;){
    num++
  }
  return num
}

但后来又意识到我并不真的需要 promise.all 尽管它的三个功能需要一些时间但可以 运行 在一起并且可以做到

function parent1(){
  console.log('start')
  console.time('ALL')
  const numsToCount = [ 140000000, 170000000, 240000000 ]
  const res = countNums(numsToCount)
  console.timeEnd('ALL')
  console.log('end', res)
}

function countNums(numsToCount){
  let countedNums = []
  for(let i = numsToCount.length; i--;){
    countedNums.push(count(numsToCount[i]))
  }
  return countedNums
}

function count(n){
  let num = 0
  for(let i = n; i--;){
    num++
  }
  return num
}

当您开始嵌套 3 次和更复杂的东西时,显然也会令人困惑,但也许尝试弄清其中一些更基本的理解将有助于解决所有问题。喜欢

const parents = [
 {name: 'Jon', pets: ['dodo', 'goofy']},
 {name: 'Tammy', pets: ['gigi', 'laffy', 'bigbird']},
 {name: 'Tom', pets: ['ralphy', 'goose']},
]

const res = await Promise.all(parents.map(async parent => {
  const res2 = await Promise.all(parent.pets.map(async pet => {
   ...
  }
}

许多示例中的等待函数是否也不同于慢速计数函数?

async function doSomething(){
  await Promise.all([wait(1000),wait(2000),wait(1500)])
  wait(1000)
}

async function wait(ms){
  return new Promise((resolve) => setTimeout(resolve, ms));
}

所以也许我在这里向你扔了很多东西,但基本上我如何实现同步编程,什么不适合速度,什么是正确使用异步和 promise.all vs 只是将所有函数传递给根据需要彼此并让功能找出所有等待前一个功能的功能。另请注意,我似乎发现 map reduce 和 filter 可能不是最快的,因为您会多次循环访问相同的数据,因此与上面的示例不同,我试图坚持更多的 for 循环,但是是的,我不希望那样分散回答问题的注意力,但这是我努力去的方向。

Promises(因此 async/await)不是获取同步代码并加速它的工具。当你创建一个承诺时,通常是因为你根本没有计算任何东西,而是在等待外部发生的事情。

例如,您可能正在等待网络响应返回,或者您可能正在等待计时器结束,或者等待某人按下某个键。发生这种情况时你不能做任何工作,所以你创建一个 Promise 然后停止 运行 任何代码。由于 javascript 是单线程的,停止 运行 您的代码对于让其他代码开始 运行 很重要,包括浏览器的正常页面绘制代码。

Promise 是具有 .then 功能的对象。你可以调用 .then 并传入一个函数来告诉它“嘿,当你完成等待时,请调用这个函数”。 async/await 只是简化了使用 promise 的语法:async 函数将自动创建一个 promise,awaiting 一个 promise 将自动调用 .then在上面。


考虑到这一点:您提供的示例与异步等待没有任何关系。你有一堆同步计算,而不是等待任何外部的东西。在 map 函数或 for 循环上使用 await 不会有任何效果,只会让你的同事感到困惑并稍微增加运行时间。