当babel处理async / await代码时,它会捆绑不相关的调用

When babel processes async / await code does it bundle unrelated calls?

本文关键字:不相关 调用 处理 babel async 代码 await      更新时间:2023-09-26

babels async/await代码是否足够聪明,可以看到下面的代码:

async function alpha () {
  let resultOne = await processNumber(5)
  let resultTwo = await processNumber(5 + 8)
  let resultThree = await processNumber(resultOne.number)
  let resultFour = await processNumber(resultOne.number + resultThree.number)
  return resultFour
}

如下所示,其中函数中的前两个承诺可以同时发生,因为执行这些操作所需的值不需要等待任何东西。

import Promise from 'bluebird'
async function beta () {
  let {resultOne, resultTwo} = await Promise.props({
    resultOne: processNumber(5),
    resultTwo: processNumber(5 + 8)
  })
  let resultThree = await processNumber(resultOne.number)
  let resultFour = await processNumber(resultOne.number + resultThree.number)
  return resultFour
}

我会理解alpha函数在它移动到下一个之前等待每个异步函数调用,在beta resultOneresultTwo同时发生的地方,这是唯一可能的,因为它们不需要等待任何其他调用。我想知道这是否真的是这样,或者babel是否在幕后做了一些事情将这些捆绑在一起。

我在两者之间设置了一个基准,似乎它本身并没有考虑到这一点。

下面是测试:

import Promise from 'bluebird'
async function processNumber (int) {
  await Promise.delay(500)
  return {number: int + 3}
}
async function alpha () {
  let resultOne = await processNumber(5)
  let resultTwo = await processNumber(5 + 8)
  let resultThree = await processNumber(resultOne.number)
  let resultFour = await processNumber(resultOne.number + resultThree.number)
  return resultFour
}
async function beta () {
  let {resultOne, resultTwo} = await Promise.props({
    resultOne: processNumber(5),
    resultTwo: processNumber(5 + 8)
  })
  let resultThree = await processNumber(resultOne.number)
  let resultFour = await processNumber(resultOne.number + resultThree.number)
  return resultFour
}
async function main () {
  const TEST_ALPHA = 'test alpha'
  const TEST_BETA = 'test beta'
  console.time(TEST_ALPHA)
  let resultAlpha = await alpha()
  console.log(resultAlpha)
  console.timeEnd(TEST_ALPHA)
  console.time(TEST_BETA)
  let resultBeta = await beta()
  console.log(resultBeta)
  console.timeEnd(TEST_BETA)
  return true
}
main()
  .then(console.log)
  .catch(console.error)

结果如下:

thomasreggi@zx:PAS-api$ babel-node test.js 
{ number: 22 }
test alpha: 2025ms
{ number: 22 }
test beta: 1508ms
true
thomasreggi@zx:PAS-api$ babel-node test.js 
{ number: 22 }
test alpha: 2033ms
{ number: 22 }
test beta: 1511ms
true

在JS中,几乎不可能做出任何严格的声明,无论给定表达式是否与另一个任意表达式"无关"(特别是静态)。

发生这种情况的原因是由于其高度动态的性质,几乎每个表达式都可能导致隐藏的(或不那么隐藏的)副作用,从而可能破坏程序的预期流程。

对于你的代码来说,如果两个"不相关"的调用"同时"触发,那么很容易破坏代码:

let isFirst = true;
async function processNumber(v) {
    await Promise.delay(2000 - v * 100);
    if (v < 10) {
        if (!isFirst) {
            throw new Error();
        }
    }
    isFirst = false;
    return { number: v + 3 };
}

alpha有效,但对beta无效。

如果你知道它会很好,并且想要"并行"运行它们,只需使用相应的await s:

async function alpha () {
  let one = processNumber(5)
  let two = processNumber(5 + 8)
  const resultOne = await one;
  let resultThree = await processNumber(resultOne.number)
  let resultFour = await processNumber(resultOne.number + resultThree.number)
  return resultFour
}

还要注意的是,resultTwo不能在代码的任何地方使用。