《Javascript 忍者秘籍》第二版,事件循环篇
promise(微任务).then()
的执行顺序优先级高于setTimeout
定时器。.then
的回调放入微任务队列;因为没有调用 resolve或者reject
之前是不算异步任务完成的, 所以不能将回调随意的放入微任务事件队列await
是一个让出线程的标志。await
后面的表达式会先执行一遍,将 await
后面的代码加入到 micro task
中这个微任务是 promise
队列中微任务,然后就会跳出整个 async
函数来继续执行后面的代码。process.nextTick
是一个独立于 eventLoop
的任务队列,主栈中的宏任务每一次结束后都是先执行 process.nextTick
队列,在执行微任务 promise
的 .then()
。
- 宏任务 macrotask
- script 整体代码
- setTimeout
- setInterval
- setImmediate
- I/O
- ui render
- 微任务 microtask
- process.nextTick
- promise.then
- await 后面的代码
- MutationObserver(h5新特性)
promise
队列中的微任务?async/await 只是操作 promise 的语法糖,最后的本质还是promise
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
// 上面的代码等价于 ==>
async function async1() {
console.log('async1 start');
Promise.resolve(async2()).then(() => {
console.log('async1 end')
})
}
面试题1
async function async1() {
console.log('1') // 2
async2().then(() => {
console.log('2')
})
}
async function async2() {
console.log('3') // 3
}
console.log('4') // 1
setTimeout(function () {
console.log('5')
}, 0)
async1();
new Promise(function (resolve) {
console.log('6') // 4
resolve();
}).then(function () {
console.log('7')
})
console.log('8') // 5
//4 1 3 6 8 2 7 5
面试题2
setTimeout(() => {
console.log(1);
}, 0);
async function main1() {
new Promise((resolve, reject) => {
console.log(2);
resolve();
}).then(() => {
console.log(3);
})
await main2();
console.log(7);
}
function main2() {
console.log(8);
}
main1();
setTimeout(() => {
console.log(10);
}, 0);
//
2
8
3
7
1
10
面试题3
Promise.resolve()
.then(() => {
console.log(0);
return Promise.resolve('4x');
})
.then((res) => { console.log(res) })
Promise.resolve().then(() => { console.log(1); })
.then(() => { console.log(2); }, () => { console.log(2.1) })
.then(() => { console.log(3); })
.then(() => { console.log(5); })
.then(() => { console.log(6); })
// 0 1 2 3 4x 5 6
面试题4 详解:(1 封私信) 关于promise输出顺序的疑问? - 知乎 (zhihu.com)
new Promise((resolve,reject) => {
console.log('外部promise')
resolve()
})
.then(() => {
console.log('外部第一个then')
new Promise((resolve,reject) => {
console.log('内部promise')
resolve()
})
.then(() => {
console.log('内部第一个then')
return Promise.resolve()
})
.then(() => {
console.log('内部第二个then')
})
})
.then(() => {
console.log('外部第二个then')
})
.then(() => {
console.log('外部第三个then')
})
.then(() => {
console.log('外部第四个then')
})
//
外部promise
外部第一个then
内部promise
内部第一个then
外部第二个then
外部第三个then
外部第四个then
内部第二个then
面试题5
// A 任务
setTimeout(() => {
console.log(1)
}, 20)
// B 任务
setTimeout(() => {
console.log(2)
}, 0)
// C 任务
setTimeout(() => {
console.log(3)
}, 10)
// D
setTimeout(() => {
console.log(5)
}, 10)
console.log(4)
/* 输出
* 4 -> 2-> 3 -> 5 -> 1
*/
面试题6
setTimeout(function () {
console.log(1)
}, 0);
new Promise(function (resolve, reject) {
console.log(2)
for (var i = 0; i < 10000; i++) {
if (i === 10) {
console.log(10)
}
i == 9999 && resolve();
}
console.log(3)
}).then(function () {
console.log(4)
})
console.log(5);
// 2, 10, 3, 5, 4, 1
面试题7
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 =>{ // flag
console.log("children7")
setTimeout(() =>{
console.log(res)
}, 0)
})
// start children4 children2 children3 children5 children7 children6
面试题8
这道题的难点在于是 promise2
还是 async1 end
先输出。从全局宏任务之上而下执行时 await async2()
后面的代码 console.log('async1 end')
先进入 promise
中的微任务队列,最后.then()
中的console.log('promise2')
再进入到 promise
中的微任务队列。所以再开始下一轮宏任务循环之前先输出了 async1 end
再输出了 promise2
。全局中的微任务执行完成开始下一轮宏任务setTimeout
最后输出 setTimeout
。
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((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
面试题9
首先开始全局下的宏任务依次输出 script start, async1 start, promise1, promise3, script end。其中 await async2();
,async2()
中.then()
的代码先进入到promise
的微任务队列,await async2();
后面的代码再进入到promise
的任务队列,console.log('promise4');
最后进入到 promise
的任务队列。全局下的宏任务结束,开始全局下的微任务,promise 的微任务队列中按照队列的先进先出原则依次输出,promise2,async1 end,promise4。全局微任务结束,开始下一轮的宏任务setTimeout
,最终输出 setTimeout
。
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function 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
面试题10
async function async1() {
console.log('async1 start');
await async2();
setTimeout(function() {
console.log('setTimeout1') // 这一部分代码会放入到 promise 的微任务队列中。
},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