async/await 中的并行串行问题

有这么两个函数

var a = function () {
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      resolve('a')
    }, 3000)
  })
}
var b = function () {
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      resolve('b')
    }, 2000)
  })
}

如果这样执行

;(async()=>{
  console.time('test')
  var aa = await a()
  var bb = await b()
  console.log(`$(aa)-${bb}`)
  console.timeEnd('test')
})()

结果是

$(aa)-b
test: 5010.7548828125ms  // 串行

但是如果这样执行

;(async()=>{
  console.time('test')
  var promiseA = a()
  var promiseB = b()
  var aa = await promiseA
  var bb = await promiseB
  console.log(`$(aa)-${bb}`)
  console.timeEnd('test')
})()

结果则是

$(aa)-b
test: 3001.277099609375ms  // 并行

这是为什么呢??

阅读 3.2k
3 个回答

因为你两个同时调用了
本来的逻辑是: a调用 等待a的三秒 然后b执行 等待b 两秒 向下执行
现在是: a,b同时调用 等待a的三秒 等待的同时b的两秒已经执行完毕 所以到b时直接往下执行

var promiseA = a()
var promiseB = b()

这样试一下

;(async () => {
    console.time('test')
    var promiseA = a()
    var aa = await promiseA
    var promiseB = b()
    var bb = await promiseB
    console.log(`$(aa)-${bb}`)
    console.timeEnd('test')
})()

其实这类语法糖,不太懂原理。建议通过 babel 转换成ES5后,再去读代码,这样便于理解。
比如上面的代码体,转换后:

串行:

while (1) {
  switch (_context.prev = _context.next) {
    case 0:
      console.time('test');
      _context.next = 3;
      return a(); // 先执行 a

    case 3:
      aa = _context.sent; // 等待a 结果,返回了。继续下一步
      _context.next = 6;
      return b(); 

    case 6:
      bb = _context.sent;

      console.log('$(aa)-' + bb);
      console.timeEnd('test');

    case 9:
    case 'end':
      return _context.stop();
  }
}

并行:

_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
  var promiseA, promiseB, aa, bb;
  return regeneratorRuntime.wrap(function _callee$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          console.time('test');
          // 所以这里是先调用,后取结果 ,其实这里如果你a,b里面有ajax调用。这里机会是顺序发送了。也就假似并行
          
          // await promiseA, await promiseB代码块获取的结果的地方,还是串行的。
          promiseA = a(); // 执行,a 
          promiseB = b(); // 执行,b
          
          _context.next = 5; // 5 
          return promiseA;

        case 5:
          aa = _context.sent;
          _context.next = 8;
          return promiseB;

        case 8:
          bb = _context.sent;

          console.log('$(aa)-' + bb);
          console.timeEnd('test');

        case 11:
        case 'end':
          return _context.stop();
      }
    }
  }, _callee, undefined);
}))();

第一种情况是串行,第二种情况,promiseA的a()和promiseB的b()同时执行,也就是promiseB的执行没有等到promiseA执行完再执行,也就是并行,所以时间比第一种情况短

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题