0%

Promise真题详解

Promise真题详解

解释会涉及到事件循环等知识点,如果这一点薄弱的可以先去了解一下事件循环

第一题

没必要上来就放大招,先来个简单的,这是我之前看文章收藏的一道题

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
28
29
console.log("start");
setTimeout(() => {
console.log("children2")
Promise.resolve().then(() => {
console.log("children3")
})
}, 0)

new Promise(function(resolve, reject) {
console.log("children4")
setTimeout(function() {
console.log("children5")
resolve("children6")
}, 0)
}).then(res => {
console.log("children7")
setTimeout(() => {
console.log(res)
}, 0)
});

//--结果--
// start
// children4
// children2
// children3
// children5
// children7
// children6
  1. 遇到这种promise题首先想到的就是出题人的需求,promise类型的题都是要执行结果,你只需要一行一行代码的分析就可以
  2. 先执行同步的代码,比如第一行的console.log("start"),所以第一个输出start
  3. 下一行执行到setTimeout,要知道,setTimeout是同步的,但是里面的回调函数是异步任务,并且要放置到宏任务队列,此时宏任务队列有一个等待执行的函数
  4. 接着下一行的new Promise(...),由于其传入的函数是立即执行的,所以第二个输出children4
  5. 下一行又遇到setTimeout,执行,里面的实参回调函数为异步任务,放到宏任务队列中,此时宏任务队列有两个等待执行的函数
  6. 有很多人会去看then,要知道由于new Promise(...)的实例对象此时还是执行中状态pending,then中的第一个回调是不执行的,所以先不考虑then
  7. 同步的任务执行完毕,先看微任务队列有没有待执行的函数,没有。去宏任务执行。第一个,也就是第一个setTimeout(...),so第三个输出children2
  8. 下一行的Promise.resolve()返回的值是成功状态的promise实例对象,并将它后面的.then(..)中的函数放到微任务队列待执行
  9. 第一个宏任务执行完毕就要去微任务队列查看是否有待执行的任务,就是说,每执行完一个宏任务都要去微任务队列看有没有任务,微任务队列清空,宏任务才执行。
  10. 此时微任务队列有一个任务,所以执行;第四个输出children3,微任务队列为空,去执行宏任务队列
  11. 接着第五个输出children5,执行了resolve(...),此时外层的new Promise()改变状态为成功态
  12. 由于外层new Promise(..)实例对象的状态改变,其.then中的第一个成功函数可以执行,并且接受的值为resolve(..)传入的实参。当然这个.then中的函数也是要放到微任务队列中的。
  13. 执行微任务队列中的任务,第六个输出children7,下一行的setTimeout(..)中的函数放到宏任务队列
  14. 查看微任务队列,空;去执行宏任务中的任务。第七个输出children6;那个res值就是上文resolve(...)传入的实参

第一题只是“开胃菜”,当然第一题如果理解的很透彻了,那么后面的题就都是”下酒菜“,这种事件循环类的题最好是画图理解,有两个队列往里面填充任务,这样看起来方面一些

第二题

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
    new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
}).then(() => {
console.log("外部第一个then");
return new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
}).then(() => {
console.log("内部第一个then");
}).then(() => {
console.log("内部第二个then");
});
}).then(() => {//注:这里返回的对象是最后一个.then返回的对象, 第一次时状态为‘pending’
//注:所以第一次这里会缓存起来并不是加入队列
console.log("外部第二个then");
});

// --结果--
// 外部promise
// 外部第一个then
// 内部promise
// 内部第一个then
// 内部第二个then
// 外部第二个then
  1. 先执行new Promise(..)中的同步任务,第一个输出外部promise
  2. 遇到resolve(),说明这个promise实例是成功状态,将其后面的第一个.then()放到微任务队列,第二个.then()由于前一个.then()还是正在执行状态,所以里面的函数暂存
  3. 执行微任务队列,第二个输出外部第一个then,触发return后面的new Promise,所以第三个输出内部promise,走到resolve(),这个promise状态改变,其后面的第一个.then()放到微任务队列,第二个.then暂存
  4. 执行微任务队列,第四个输出内部第一个then,而then()中的函数默认return一个新的Promise实例,所以第二个.then()中的函数放到微任务队列。并且执行第五个输出内部第二个then,同时return一个新的Promise实例对象。
  5. 这时候最外层的第一个.then()有return新的Promise,所以第二个.then()放到微任务队列。
  6. 执行微任务队列,所以第六个输出外部第二个then

第三题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    new Promise((resolve, reject) => {
console.log("外部promise");
resolve();
}).then(() => {
console.log("外部第一个then");
new Promise((resolve, reject) => {
console.log("内部promise");
resolve();
}).then(() => {
console.log("内部第一个then");
}).then(() => {
console.log("内部第二个then");
});
}).then(() => {
console.log("外部第二个then");
});

// --结果--
// 外部promise
// 外部第一个then
// 内部promise
// 内部第一个then
// 外部第二个then
// 内部第二个then

这一题其实就是第二题修改版

  1. 首先执行new Promise()内的同步任务,第一个输出外部promise,遇到resolve(),new Promise变成成功状态,后面的第一个.then()放到微任务队列,第二个.then()暂存。
  2. 执行微任务队列第二个输出外部第一个then,执行new Promise()中的同步任务,所以第三个输出内部promise,遇到resolve()状态改变,后面的第一个.then()放到微任务队列,后面的.then()暂存。
  3. 此时这个正在执行的.then()return的是undefined,所以外面的最后一个.then(),放到微任务队列。
  4. 执行微任务队列第一个,所以第四个输出内部第一个then,并且return的也是一个undefined,后面的.then()也放到微任务队列
  5. 接着执行下一个微任务队列中的任务,也就是最外层的.then()中的函数,第五个输出外部第二个then
  6. 最后一个微任务,也就是最内层的.then()第六个输出内部第二个then

更多题…..

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
28
29
30
31
32
33
34
35
36
37
38
async function async1() {
console.log("async1 start")
await async2();
//await async2(), 这里的代码相当于new Promise(()=>{async2()})
//而将 await 后面的全部代码放到.then()中去
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
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
28
console.log("start");
setTimeout(() => {
console.log("children2")
Promise.resolve().then(() => {
console.log("children3")
})
}, 0)

new Promise(function(resolve, reject) {
console.log("children4")
setTimeout(function() {
console.log("children5")
resolve("children6")
}, 0)
}).then(res => {
console.log("children7")
setTimeout(() => {
console.log(res)
}, 0)
});

// start
// children4
// children2
// children3
// children5
// children7
// children6
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
28
29
30
31
32
33
34
35
36
37
38
39
40
var p = new Promise(resolve => {
console.log(4);
resolve(5);
}).then(resolve => {
console.log(resolve);
});

function func1() {
console.log(1);
};

function fun2() {
setTimeout(() => {
console.log(2);
});
func1();
console.log(3);

new Promise(resolve => {
resolve();
}).then(resolve => {
console.log('新的resolve');
})

p.then(resolve => {
console.log(7);
}).then(resolve => {
console.log(6);
});
}
fun2()

// 4
// 1
// 3
// 5
// 新的resolve
// 7
// 6
// 2
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
async function async1() {
console.log('async1 start');
const result = await async2();
console.log(result);
// 会先执行async2函数, 然后跳出async1, 同时将返回的promise放入微队列
console.log('async1 end');
}
async function async2() {
console.log('async');
return "testAwait";
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
new Promise(function(resolve) {
console.log('promise3');
resolve();
}).then(function() {
console.log('promise4');
});
console.log('script end');

// script start
// async1 start
// async
// promise1
// promise3
// script end
// testAwait
// async1 end
// promise2
// promise4
// setTimeout