为了账号安全,请及时绑定邮箱和手机立即绑定

《前端面试手记》之谈谈promise/async/await的执行顺序

👇 内容速览 👇

  • 题目和答案
  • 输出解释
  • 再谈谈async/await
  • 最新的v8和谷歌浏览器的正确输出

1. 题目和答案

故事还是要从下面这道面试题说起:请问下面这段代码的输出是什么?

console.log('script start')

async function async1() {
  await async2()
  console.log('async1 end')
}

async function async2() {
  console.log('async2 end')
}
async1()

setTimeout(function() {
  console.log('setTimeout')
}, 0)

new Promise(resolve => {
  console.log('Promise')
  resolve()
})
  .then(function() {
    console.log('promise1')
  })
  .then(function() {
    console.log('promise2')
  })

console.log('script end')

上述,在Chrome 66node v10中,正确输出是:

script start
async2 end
Promise
script end
promise1
promise2
async1 end
setTimeout

注意:在新版本的浏览器中,await输出顺序被“提前”了,请看官耐心慢慢看。

2. 流程解释

边看输出结果,边做解释吧:

  1. 正常输出script start
  2. 执行async1函数,此函数中又调用了async2函数,输出async2 end。回到async1函数,遇到了await,让出线程
  3. 遇到setTimeout,扔到下一轮宏任务队列
  4. 遇到Promise对象,立即执行其函数,输出Promise。其后的resolve,被扔到了微任务队列
  5. 正常输出script end
  6. 此时,此次Event Loop宏任务都执行完了。来看下第二步被扔进来的微任务,因为async2函数是async关键词修饰,因此,将await async2后的代码扔到微任务队列中
  7. 执行第4步被扔到微任务队列的任务,输出promise1promise2
  8. 执行第6步被扔到微任务队列的任务,输出async1 end
  9. 第一轮EventLoop完成,执行第二轮EventLoop。执行setTimeout中的回调函数,输出setTimeout

3. 再谈async和await

细心的朋友肯定会发现前面第6步,如果async2函数是没有async关键词修饰的一个普通函数呢?

// 新的async2函数
function async2() {
  console.log('async2 end')
}

输出结果如下所示:

script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout

不同的结果就出现在前面所说的第6步:如果await函数后面的函数是普通函数,那么其后的微任务就正常执行;否则,会将其再放入微任务队列。

4. 其实是V8引擎的BUG

看到前面,正常人都会觉得真奇怪!(但是按照上面的诀窍倒也是可以理解)

然而V8团队确定了这是个bug(很多强行解释要被打脸了),具体的PR请看这里。好在,这个问题已经在最新的Chrome浏览器中被修复了

简单点说,前面两段不同代码的运行结果都是:

script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout

await就是让出线程,其后的代码放入微任务队列(不会再多一次放入的过程),就这么简单了。

更多系列文章

《前端知识体系》

《设计模式手册》

《Webpack4渐进式教程》

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
23
获赞与收藏
81

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消