fe-learning icon indicating copy to clipboard operation
fe-learning copied to clipboard

关于async和await的“同步”

Open metroluffy opened this issue 5 years ago • 1 comments

关于async和await的“同步”

题目

要求看代码写输出。

function wait(){
  return new Promise(resolve =>
    setTimeout(resolve, 10*1000)
  )
}
async function func1() {
  console.time('time-func1')
  const x = await wait()
  const y = await wait()
  const z = await wait()
  console.timeEnd('time-func1')
}
async function func2() {
  console.time('time-func2')
  const x = wait()
  const y = wait()
  const z = wait()
  await x
  await y
  await z
  console.timeEnd('time-func2')
}
func1()
func2()

/** 输出如下
 * time-func2:10002.4ms
 * time-func1: 32261.5ms
 */

解析

async、await语法糖让我们可以把Promise的异步回调处理写出“同步”的方式,即代码看起来是同步并且整洁很多,但其目的是简化使用多个 promise 时的同步行为,并非是真同步。

await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行 async function。

如此相邻的两个 await wait() 会形成继发关系(串行)。要写成并发方式,~~可以如 func2函数所示用变量先缓存Promise,再一起执行~~,或者你也可以使用 Promise.all / Promise.allSettled,没有依赖关系的函数最好让它们同时触发。

注意:Promise.all 有短路效应,如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 promise 的结果。

async function func3() {
  console.time('time-func3')
  await Promise.all([wait(),wait(),wait()])
  console.timeEnd('time-func3')
}
func3()
// time-func3: 10455.867919921875ms

更多请参见: MDN-async function

metroluffy avatar Apr 27 '20 13:04 metroluffy

这里的解析存在问题,真实情况应该是Promise constructor同步执行,await则会暂停当前async执行直到结果返回,相对而言,串行变成了并发。

metroluffy avatar Mar 05 '21 07:03 metroluffy