由一道面试题引出:javascript
//请写出输出内容 async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { console.log('async2'); } console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0) async1(); new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); console.log('script end'); /* script start async1 start async2 promise1 script end async1 end promise2 setTimeout */复制代码
在理清楚如下几个知识点后上面问题就迎刃而解了:java
1. 宏任务:包括script(总体代码),setTimeout,setInterval,I/O,UI交互,postMessagegit
2. 微任务:包括promise.then,MutationObservergithub
3. 执行过程: a) 执行一个宏任务 b)过程当中遇到微任务,则添加其到微任务队列 c)当前宏任务执行完以后,开始依次执行全部微任务 d)GUI线程接管开始渲染 e)渲染完成交给js线程重复这个过程面试
4. async标志的函数里面,只有当await的表达式返回结果后,await之后的代码才会被执行promise
5. async/await实际上是promise的语法糖,因此await之后的代码至关于放入了then里面浏览器
1. 代码开始,宏任务是scriptbash
Macro tasks
---------------
| script |
---------------复制代码
2. 从上往下,首先看到了同步代码log,则输出 script start
markdown
3. 遇到settimeout,将其里面的内容加入宏任务队列async
Macro tasks ---------------------------------- | script | log 'setTimeout' | ----------------------------------复制代码
4. 运行async1函数,没遇到await以前都是同步代码,输出 async1 start
5. 遇到await,解析成以下形式
Promise.resolve(async2()).then(() => {console.log('async1 end')})复制代码
6. async2由于直接返回值无需等待,因此输出 async2
7. 如上改写能够看出那句log被放入了微任务队列
Macro tasks queue ---------------------------------- | script | log 'setTimeout' | ---------------------------------- Micro tasks queue ----------------------- | log 'async1 end' | -----------------------复制代码
8. 遇到new promise实例化过程,此过程依然是同步的,输出promise1
,并把then的内容加入微队列
Macro tasks queue ---------------------------------- | script | log 'setTimeout' | ---------------------------------- Micro tasks queue ------------------------------------------- | log 'async1 end' | log 'promise2' | -------------------------------------------复制代码
9. 输出同步log:script end
10. 此时已经到了script这个宏任务的最后了,开始执行其全部微任务,清空微任务队列,输出async1 end
,promise2
Macro tasks queue ---------------------------------- | script | log 'setTimeout' | ---------------------------------- Micro tasks queue ------------------------------------------- | | -------------------------------------------复制代码
11. script宏作完,本身出队列
Macro tasks queue ---------------------------------- | log 'setTimeout' | ---------------------------------- Micro tasks queue ------------------------------------------- | | -------------------------------------------复制代码
12. 浏览器开始渲染,渲染完成开始下一个宏任务
13. 输出setTimeout
, 清空宏队列,完成!
这种题就算知道了解法,也推荐画图,否则很容易晕
async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { //async2作出以下更改: new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); } console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0) async1(); new Promise(function(resolve) { console.log('promise3'); resolve(); }).then(function() { console.log('promise4'); }); console.log('script end');复制代码
// 答案 script start async1 start promise1 promise3 script end promise2 async1 end promise4 setTimeout复制代码
settimeout加入宏队列,promise1在实例化时输出,promise2和async1 end加入微队列 Macro tasks queue Micro tasks queue --------------------------- ------------------------------ | script | setTimeout | | promise2 | async1 end | --------------------------- ------------------------------ promise3输出,promise4加入微队列 ------------------------- --------------------------------------- | script | settimeout | | promise2 | async1 end | promise4 | ------------------------- ---------------------------------------复制代码
另外一个
async function async1() { console.log('async1 start'); await async2(); //更改以下: setTimeout(function() { console.log('setTimeout1') },0) } async function async2() { //更改以下: setTimeout(function() { console.log('setTimeout2') },0) } console.log('script start'); setTimeout(function() { console.log('setTimeout3'); }, 0) async1(); new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }); console.log('script end');复制代码
// 答案 script start async1 start promise1 script end promise2 setTimeout3 setTimeout2 setTimeout1复制代码
settimeout3加入宏队列,settimeout2也加入宏,注意此时后面总体代码加入微队列 Macro tasks queue Micro tasks queue ------------------------------------------- ------------------------------ | script | setTimeout3 | settimeout2 | | setTiemout(settimout1) | ------------------------------------------- ------------------------------ promise3输出,promise4加入微队列 ----------------------------------------- ----------------------------------------- | script | settimeout3 | settimeout2 | | setTimeout(settimeout1) | promise2 | ----------------------------------------- ----------------------------------------- script end输出后开始执行微队列,setTimoue被取出执行,把settimeout1加入宏队列 -------------------------------------------------- -------------- | script | setimeout3 | settimeou2 | settimeout1 | | promise2 | -------------------------------------------------- -------------复制代码
另外一个
async function a1 () { console.log('a1 start') await a2() console.log('a1 end') } async function a2 () { console.log('a2') } console.log('script start') setTimeout(() => { console.log('setTimeout') }, 0) Promise.resolve().then(() => { console.log('promise1') }) a1() let promise2 = new Promise((resolve) => { resolve('promise2.then') console.log('promise2') }) promise2.then((res) => { console.log(res) Promise.resolve().then(() => { console.log('promise3') }) }) console.log('script end')复制代码
// 答案 script start a1 start a2 promise2 script end promise1 a1 end promise2.then promise3 setTimeout复制代码
这跟上面差很少,只不过把promise2分开写,实例化是同步的因此先运行log promise2
原文: