一、几个关键问题:
1、宏队列:用来保存待执行的宏任务(回调),比如:定时器回调、DOM事件回调、ajax回调。
2、微队列:用来保存待执行的微任务(回调),比如:promise的回调、MutationObserver的回调。
3、JS执行时,必须先执行所有的同步任务代码,然后将微队列中的任务取出执行,当所有微任务执行完成以后,再取出宏队列中的代码执行。所以执行顺序是:同步任务---->微队列任务---->宏队列任务。
4、Promise((resolve, reject) => { resolve(1) }).then(()=>{console.log(1)})中(resolve, reject) => {}是同步执行的,.then()也是同步执行,但是.then()中的回调函数是异步执行。
5、类似与.then(()=>{console.log(1)}).then(()=>{console.log(2)})这样的结构,第一个.then中有return之后,第二个.then中的函数才会执行。(如果.then()中没有人为指定return,系统会默认return undefined)。
6、await右侧的表达式一般为promise对象但也可以是其他值,如果是promise对象,await返回promise成功值,如果表达式是其他值,则直接将此值作为await的返回值。
7、await必须写在async函数中,但async函数中可以没有await
二、几道考执行顺序的题
1、给出以下代码的执行结果
setTimeout(() => {
console.log("0")
}, 0)
new Promise((resolve, reject) => {
console.log("1")
resolve()
}).then(() => {
console.log("2")
new Promise((resolve, reject) => {
console.log("3")
resolve()
}).then(() => {
console.log("4")
}).then(() => {
console.log("5")
})
}).then(() => {
console.log("6")
})
new Promise((resolve, reject) => {
console.log("7")
resolve()
}).then(() => {
console.log("8")
})
答案: 1,7,2,3,8,4,6,5,0
解析:
(1)按顺序往下看,定时器先执行console.log("0")进入宏队列等待。//此时输出:[ ],微队列:[ ],宏队列:[0]
(2)与promise同步执行的(resolve, reject) => {},输出1,resolve执行完执行.then,then中为回调函数进入微队列等待。//此时输出:[1],微队列:[2],宏队列:[0]
(3)第三个promise执行,同步执行(resolve, reject) => {},输出7,resolve执行完执行.then,then中为回调函数,故console.log(8)进入微队列进行等待。//此时输出:[1,7],微队列:[2,8],宏队列:[0]
(4)此时最外层已经没有需要同步执行的代码了,所以执行微队列中的第一个回调函数,输出2并执行new promise。//此时输出:[1,7,2],微队列:[8],宏队列:[0]
(5)new promise中的(resolve, reject) => {}同步执行,输出3执行resolve(),并且后面的所有.then也同步执行,但需注意.then是同步执行是因为promise().then().then()是同一级的。但是.then()中的回调函数需等到上一级的函数或.then有返return了才开始执行。所以此时console.log(4)进入微队列。new promise()执行完成故上一层.then()执行完成return undefined 。故与它相连的.then()中的回调函数执行 console.log(6) 进入微队列。 //此时输出:[1,7,2,3],微队列:[8,4,6],宏队列:[0]
(6)此时该层已经没有需要同步执行的代码了,微队列执行打印8,然后执行打印4。//此时输出:[1,7,2,3,8,4],微队列:[6],宏队列:[0]。
(7)console.log(4)执行完成后,与它同一级的.then()得到返回值,其中的回调函数开始执行console.log(5)进入微队列。//此时输出:[1,7,2,3,8,4],微队列:[6,5],宏队列:[0]。
(8)此时该层已经没有需要同步执行的代码了,微队列执行,打印6,打印5,微队列执行完毕。//此时输出:[1,7,2,3,8,4,6,5],微队列:[ ],宏队列:[0]。
(9)所有微队列执行完毕,执行宏队列,打印5。//此时输出:[1,7,2,3,8,4,6,5,0],微队列:[ ],宏队列:[]。
2、给出以下代码的执行结果
async function async1() {
console.log('1');
await async2();
console.log('2');
}
async function async2() {
console.log('3');
}
console.log('4');
setTimeout(()=>{
console.log('5');
},0)
async1();
new Promise((resolve)=>{
console.log('6');
resolve();
}).then(()=>{
console.log('7');
});
console.log('8');
答案:4 、1、3、6、8、2、7、5
解析:
(1)按顺序执行,先执行同步代码console.log(4) //输出:[4],微队列:[ ],宏队列:[ ]
(2)setTimeout执行,进入宏队列。 //输出:[4],微队列:[ ],宏队列:[5]
(3)执行async1,同步执行sonsole.log(1),执行async2,console.log(2)进入微队列等待,async2同步执行console.log(3)。//输出:[4,1,3],微队列:[2],宏队列:[5]。
(4)下一个new promise中的(resolve, reject) => {}同步执行打印6,执行resolve以及.then()中的回调函数,console.log(7)进入微队列等待。 //输出:[4,1,3,6],微队列:[2,7],宏队列:[5]
(5)顺序执行同步代码console.log(8)。 //输出:[4,1,3,6,8],微队列:[2,7],宏队列:[5]。
(6)此时最外层的同步代码均已执行完毕,执行微队列,打印2,7,微队列执行完毕,执行宏队列打印5。 //输出:[4,1,3,6,2,7,5],微队列:[ ],宏队列:[ ]
3、给出以下代码的执行结果
(async function () {
await console.log(1);
console.log(2);
})().then(
() => console.log(1)
);
console.log(4);
setTimeout(function () {
console.log(5);
}, 0)
答案:1,4,2,1,5
知识点:
(1)(function fun(a,b,c){})(1,2,3) 小括号中的函数会被解析成表达式,1,2,3会被解析为函数的实参
(2)async和await。
(3)微队列和宏队列。
解析:
(1)await后面的console.log(1)先执行,console.log(2)进入微队列等待。 //[1]
(2)执行同步任务console.log(4)。 //[1,4]
(3)console.log(5)进入宏队列等待。//[1,4]
(4)同步任务以全部执行完,console.log(2)出微队列执行,async function(){}全部执行完毕.then中的1进入微队列等待。//[1,4,2]
(5)由于没有其他同步任务和微队列要执行,所以从微队列中取出1。 //[1,4,2,1]
(6)所有微队列都执行完毕,从宏队列中取出5。 //[1,4,2,1,5]