EventLoop遇上Promise

面试时的EventLoop/Promise难度进阶

版本一:得心应手版

1
2
3
4
5
6
7
setTimeout(()=>{
console.log(1)
},0)
Promise.resolve().then(()=>{
console.log(2)
})
console.log(3)

考察点:了解宏任务(marcotask)微任务

版本二:游刃有余版

1
2
3
4
5
6
7
8
9
10
11
12
setTimeout(()=>{
console.log(1)
},0)
let a=new Promise((resolve)=>{
console.log(2)
resolve()
}).then(()=>{
console.log(3)
}).then(()=>{
console.log(4)
})
console.log(5)

考察点:Promise的理解程度

版本三:炉火纯青版

首先理解一下以下执行(这个更好理解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 题1
new Promise((resolve,reject) => {
console.log("promise1")
resolve()
}).then(() => {
console.log("then11")
}).then(() => {
console.log("then12")
}).then(() => {
console.log("then13")
})
new Promise((resolve,reject) => {
console.log("promise2")
resolve()
}).then(()= > {
console.log("then21")
}).then(() => {
console.log("then23")
}).then(() => {
 console.log("then24")
}).then(() => {
 console.log("then25")
})
1
2
3
4
5
6
7
8
9
// 输出
promise1
promise2
then11
then21
then12
then23
then24
then25

then返回的promise要等该then注册的回调执行完才resolve

按我能现在接受的理解是:new Promise(fn)fn毫无疑问是立即执行的,(resolve是异步),之后所有then同步执行完,返回Promise{<pending>},(期间注册回调,注意不是放到microqueue中,只是放到promisecallback属性中)每个promise都在等待resolve后变为fulfilled才把注册的回调microtask(fn),立刻放到微任务队列中,如此循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 题2
new Promise((resolve,reject) => {
console.log("promise1")
resolve()
}).then(() => {
console.log("then11")
new Promise((resolve,reject) => {
console.log("promise2")
resolve()
}).then(() => {
console.log("then21")
}).then(() => {
console.log("then23")
}).then(() => {
 console.log("then24")
}).then(() => {
 console.log("then25")
})
}).then(() => {
 console.log("then12")
}).then(() => {
 console.log("then13")
})
// 抛开同步执行的`promise1`和`promise2`,结果和题2是一致的
// new Promise resolve后then回调会立即入队,遇到new promise理解执行函数中如果resolve效果感觉是同步的,会让then回调立即入队。
1
2
3
4
5
6
7
8
9
// 输出
promise1
then11
promise2
then21
then12
then23
then24
then25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 题3 - 检验上面的理解
new Promise((resolve,reject)=>{
console.log("promise1",1)
resolve()
}).then(()=>{
console.log("then11",2)
new Promise((resolve,reject)=>{
console.log("promise2",3)
resolve();
}).then(()=>{
console.log("then21",4)
new Promise((resolve,reject)=>{
console.log("promise3",5)
resolve();
}).then(()=>{
console.log("then31",7)
}).then(()=>{
console.log("then32",9)
})
}).then(()=>{
console.log("then22",8)
})
}).then(()=>{
console.log("then12",6)
})
// 按照上面的理解是可以解释这一题的
// 即入队顺序:then11 -> then21 -> then12 -> then31 -> then22 -> then32

做到心中有队列(current stack 和 micro stack一直在):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 题4
new Promise((resolve,reject)=>{
console.log("promise1")
resolve()
}).then(()=>{
console.log("then11")
return new Promise((resolve,reject)=>{
console.log("promise2")
resolve()
}).then(()=>{
console.log("then21")
}).then(()=>{
console.log("then23")
})
}).then(()=>{
console.log("then12")
})
1
2
3
4
5
6
7
// 输出
promise1
then11
promise2
then21
then23
then12

版本四:登峰造极版

考点:在async/await之下,对Eventloop的影响

槽点:别被async/await给骗了,这题不难。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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')
1
2
3
4
5
6
7
8
9
// 输出
script start
async1 start
async2
promise1
script end
async1 end
promise2
settimeout

这里该题作者给的解释:

await async2()相当于一个Promiseconsole.log("async1 end");相当于前方Promisethen之后执行的函数

此处唯一有争议的就是asyncthenpromisethen的优先级的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async function async1() {
console.log("async1 start")
await async2()
console.log("async1 end")
}
async function async2() {
console.log('async2')
}
async1()
// 用于test的promise,看看await究竟在何时执行
new Promise(function (resolve) {
console.log("promise1")
resolve()
}).then(function () {
console.log("promise2")
}).then(function () {
console.log("promise3")
}).then(function () {
console.log("promise4")
}).then(function () {
console.log("promise5")
})
1
2
3
4
5
6
7
8
9
// 输出
async1 start
async2
promise1
async1 end
promise2
promise3
promise4
promise5
-------------要说再见啦感谢大佬的光临~-------------