【问题标题】:When is async, await, promise.all needed in JavaScript?JavaScript 什么时候需要 async、await、promise.all?
【发布时间】:2021-02-01 23:54:42
【问题描述】:

我正在努力提高代码性能,但经过多年的编码,我发现自己对一些基础知识感到困惑。 当然,我们基本上有需要按顺序运行的东西(异步函数)和并行的东西(只是正常的同步函数)。我阅读了有关 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
}

但实际上我认为它不是我需要传递给下一个函数才能使其工作的值,所以它基本上没问题,无需等待响应,因为它基本上发送一个函数作为参数,如

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 来加快并发运行的函数的速度,并且它所采用的函数应该是异步的,因为它以类似的方式返回一个 Promise

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));
}

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

【问题讨论】:

    标签: javascript performance promise async-await synchronization


    【解决方案1】:

    Promise(以及因此 async/await)不是采用同步代码并加快其速度的工具。当你创建一个 Promise 时,通常是因为你根本没有计算任何东西,而是在等待外部的事情发生。

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

    Promises 是带有.then 函数的对象。你可以调用.then 并传入一个函数来告诉它“嘿,等你等完了,请调用这个函数”。 async/await 只是简化了使用 Promise 的语法:async 函数会自动创建一个 Promise,await一个 Promise 会自动调用 .then


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

    【讨论】:

    • 感谢您澄清这一点,我确实对异步感到困惑,超出了预期!没有意识到 async 不能与内部正常的 js 函数一起使用,但是对于 fetch 调用是有意义的
    猜你喜欢
    • 2020-09-03
    • 2018-06-27
    • 2017-10-26
    • 1970-01-01
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    相关资源
    最近更新 更多