由一道面试题引出: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
async
3. 遇到settimeout,将其里面的内容加入宏任务队列函数
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
原文: