【问题标题】:When babel processes async / await code does it bundle unrelated calls?当 babel 处理 async / await 代码时,它会捆绑不相关的调用吗?
【发布时间】:2016-11-15 21:11:56
【问题描述】:

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
}

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

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 是否在幕后做了一些事情来将这些捆绑在一起。

【问题讨论】:

  • “足够聪明,可以看到下面的代码”——它足够聪明,看不到。这两个例子是不同的,实现processNumber确实没有问题,所以2个代码样本返回了不同的结果。

标签: javascript async-await babeljs


【解决方案1】:

我在两者之间设置了一个基准,但它本身似乎并不能说明这一点。

这是测试:

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

【讨论】:

    【解决方案2】:

    在 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

    如果您知道这很好并且想要“并行”运行它们,只需相应地使用awaits:

    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 不会在您的代码中的任何地方使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-13
      • 2021-10-24
      • 2019-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多