面试被虐,很正常的事,感觉很爽,你会发现,自己又可以提升自身技术了,不知道你们有没有这种体会?

一道精心策划的面试题背后,可以有无数种玩法,有些玩法甚至换汤不换药,废话不多说,直接还原面试场景。

面试官:了解 promise 和 Generator 吗?

我:了解,并看过源码,理解其原理。

面试官:那你说说 async/await 和 peomise 的执行顺序。

不是正要准备问我 promise 吗?面试官怎么不按套路出牌呢?

幸好有准备,吧啦吧啦说完他们之间的关系和执行顺序,此时出现了一道笔试题,如下:

 1async function async1() { 2  console.log( 'async1 start' ) 3  await async2() 4  console.log( 'async1 end' ) 5} 6async function async2() { 7  console.log( 'async2' ) 8} 9console.log( 'script start' )10setTimeout( function () {11  console.log( 'setTimeout' )12}, 0 )13async1();14new Promise( function ( resolve ) {15  console.log( 'promise1' )16  resolve();17} ).then( function () {18  console.log( 'promise2' )19} )20console.log( 'script end' )

关于异步编程,网上很多的文章来总结,对于我来说,大学做项目的时候很少用到 async/await,所以正好借助这道面试题,深入了解一下它。

这道题难就难在不仅说出执行顺序,而且要说明为什么?

答案主要是以浏览器的 EventLoop 机制为准的,所以就以浏览器环境为主来分析。

对于 Promise 就不多 BB 了,之前小鹿写的前端面试小册上写了,公众号后台回复「PDF」获取!

1、什么是 async/await?

其实 ES7 中的 async 及 await就是 Generator 以及 Promise 的语法糖,内部的实现原理还是原来的,只不过是在写法上有所改变,这些实现一些异步任务写起来更像是执行同步任务。

只要是函数前带 async 关键词,说明这个函数一定返回一个 Promise 对象。

 1async function fn1(){ 2    return '小鹿动画学编程' 3} 4 5function fn2(){ 6    return '小鹿动画学编程' 7} 8 9console.log(fn1()) // Promise { '小鹿动画学编程' }10console.log(fn2()) // 小鹿动画学编程

如果 async 关键字函数返回的不是 promise,会自动用 Promise.resolve()包装;如果 async 关键字函数显式地返回 promise,那就以返回的 Promise 为主。

为了更好的记住它,async 函数不就是比普通的函数执行后,返回值被包装成了 promise 对象返回吗。

除此之外,async 就是有异步的意思,说明函数内部存在异步的操作,函数内部使用关键字 await 主要是干嘛的呢?

2、await 是干什么的?

await 中文是等待的意思,这里我们理解为等待右边的表达式返回的结果。如果该表达式是一个值类型,那么表达式的值就是这个值;如果表达式是一个函数,那么等待的结果就是函数返回值。

 1async function async1() { 2    console.log( 'async1 start' ) 3    await async2() 4    console.log( 'async1 end' ) 5} 6async function async2() { 7    console.log( 'async2' ) 8} 9async1()10console.log( 'script start' )

上述代码的执行顺序是什么呢?这涉及到了浏览器 EventLoop 的执行顺序和规则。

一般我们误认为程序遇到 await 就会阻塞当前的函数执行,所以此时 async2 不会执行而是 script start 先执行。经过运行之后,控制台先打印的 async2,后打印的 script start。

我们可以总结总结一下,其实程序执行,执行完 async2 之后,发现前边有一个 await 关键词,此时 async2 已经执行,所以会阻塞后边的代码。


3、await (静静等着你)

当我们 await 等待表达式的等待结果的时候,分为两种情况,一种是 peomise 对象;一种是非 promise 对象。

如果表达式返回的等待的结果不是 promise,await 会阻塞后边的代码执行,此时跳出 async 函数,执行外面的同步代码,所有的同步代码执行完成之后,再把返回非 promise 结果作为 await 的等待结果。

如果表达式返回的等待的结果是 promise 对象,那么 await 也会暂停 async 后续的代码,执行 async 外的同步代码。当等到 promise 执行 fulfilled,把 resolve 的参数作为 await 的返回结果。

4、EventLoop 的执行过程

(来自小鹿的前端面试小册子)

有过浏览器的 EventLoop 不在多啰嗦,直接看面试原题。

5、头条面试原题解析

 1async function async1() { 2  console.log( 'async1 start' ) 3  await async2() 4  console.log( 'async1 end' ) 5} 6async function async2() { 7  console.log( 'async2' ) 8} 9console.log( 'script start' )10setTimeout( function () {11  console.log( 'setTimeout' )12}, 0 )13async1();14new Promise( function ( resolve ) {15  console.log( 'promise1' )16  resolve();17} ).then( function () {18  console.log( 'promise2' )19} )20console.log( 'script end' )

代码执行,script 同步代码执行,所以首先输出同步代码 "script start"。

遇到 setTimeout 进入宏任务队列,调用 async1() ,输出 "async1 start",开始执行 async2 。

执行到 await async2() ,先计算 async2() 打印 "async2",看到 await 阻塞后边代码,跳出当前函数.

开始执行同步代码中的 new Promise,new Promsie 构造函数中是同步的代码,输出 "promise1"。

程序继续运行,直到遇到 promise.then 是微任务,进入到微任务队列中。

最后打印同步代码 “script end”,执行完所有同步代码之后,回到之前被阻塞的 async 函数中的 await 表达式中。上边提到过,如果返回的是 Promise,那么当等到 promise 执行 fulfilled,把 resolve 的参数作为 await 的返回结果。

1await Promise.resolve(undefined)

所以就相当于执行上述代码,我们想要拿到执行的结果,需要在 then 的参数中获取,调用 resolve 的时候,会把 then 放到微任务队列。

await async2 执行结束后,才能执行后边的代码。当前宏任务1执行完毕,开始处理所有的微任务,微任务遵循先进先出的原则,打印微任务1 "promise2",微任务2 什么都没有打印。

微任务执行完毕后,await async2 执行完毕,后边的代码不在阻塞,打印 “async1 end”。

然后进行下一次消息循环,执行宏任务队列,打印 “setTimeout” 所有任务执行完成,程序结束。

注意:不同浏览器测试的结果是不相同的,跟浏览器的版本相关!


一个三本混出来的程序员,维护着一个既有技术又有温度的原创号,一直认为能把复杂的东西讲明白是一件很牛逼的事情。

©著作权归作者所有:来自51CTO博客作者mb5fe1601ede528的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. Python 为什么使用缩进来划分代码块?
  2. 学编程这么久,还傻傻分不清什么是方法(method),什么是函数(function)?
  3. 这外包代码写的真烂,这次坑惨我了!
  4. 入职第二天,老大就让我重构代码!
  5. 用Python写几行代码,一分钟搞定一天工作量,同事直呼:好家伙!
  6. Python发送邮件基础知识与代码讲解!
  7. 秒懂!图解四个实用的Pandas函数!
  8. 一个真实问题,搞定三个冷门pandas函数
  9. 原理+代码|详解层次聚类及Python实现

随机推荐

  1. 怎样搭建Android开发平台
  2. Windows下Camtasia Studio的安装与卸载
  3. android 开发技巧(5)--使 用 TextSwitche
  4. 【Android小经验】android:gravity和andr
  5. Android中webView与h5交互
  6. Android和Linux关系
  7. Android CTS 兼容性测试
  8. Android 核心分析 之五 -----基本空间划
  9. Android位图总结
  10. 【Android Studio使用教程3】Android Stu