首先是一道今日头条的面试题:(听说是今日头条的并且已经烂大街了)
1 async function async1() { 2 console.log( 'async1 start' ) 3 await async2() 4 console.log( 'async1 end' ) 5 } 6 7 async function async2() { 8 console.log( 'async2' ) 9 } 10 11 console.log( 'script start' ) 12 13 setTimeout( function () { 14 console.log( 'setTimeout' ) 15 }, 0 ) 16 17 async1(); 18 19 new Promise( function ( resolve ) { 20 console.log( 'promise1' ) 21 resolve(); 22 } ).then( function () { 23 console.log( 'promise2' ) 24 } ) 25 26 console.log( 'script end' )
这个题我认为的顺序和浏览器的顺序一开始并不一样,让我一度以为浏览器出了问题。
首先需要了解promise,不然后面就很难理解下去。参见:http://es6.ruanyifeng.com/#docs/promise
async是什么?
简单来讲如果一个函数前面带了async那么,函数的返回值必定是一个promise的对象。如果返回值不是promise对象,会自动的去包装为一个promise对象。
await是什么?
await可以算是async wait简写。等待async执行结果。
回到代码中,显而易见首先打印的内容是‘script start’,不需要解释。
然后就是setTimeout,虽然时间是0但是只有在这一轮事件循环的底部或者是事件队列为空才会立即执行,很明显既不是底部,事件队列也还未执行完成。
下一个执行到async1();
在async1中首先打印‘async1 start’,然后遇到await,await会阻塞后面的代码,先执行async外部的代码,所以会接着打印‘async2’;
之前的await中断了当前async的执行,所以下一个执行的就是promise,promise是直接调用同步代码,所以接着就是‘promise1’;
因为会优先执行同步代码,所以接下来就是打印‘script end’;
执行完毕回到promise接着执行then打印‘promise2’,之后再次回到前面继续执行resolve,但是因为参数为空,所以打印‘undefined’;(promise执行顺序,具体参见:http://es6.ruanyifeng.com/#docs/promise)
这个时候await async2()执行结束,继续async1后面的代码,打印‘async1 end’;
至此所以的事件队列执行结束
前面说了,事件队列为空才会执行setTimeout。
所以正确的顺序为:
script start async1 start async2 promise1 script end promise2 async1 end setTimeout
有错误的话欢迎指正。