【面试题】JS的EventLoop还不会?(一)
在了解JS消息队列之前,首先要知道不同的异步任务会被分为两类:宏任务和微任务
常见的宏任务有:setTimeout
,setInterval
,DOM事件
,AJAX请求
常见的微任务有:Promise.then
,async/await
,process.nextTick
大原则:先执行完所有的微任务,再执行宏任务。
当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
所以执行步骤就是:
从上往下执行主线程的任务(console,new Promise , ........)
从上往下找到微任务,加入到微任务队列
从上往下找到宏任务,加入到宏任务队列
第一次循环结束后,最外层的主线程任务应该全部都已经完成
将微任务队列中的任务挨个执行
此时可能微任务内有微任务,宏任务和主线程,都将其加入到自己对应的队列中
微任务全部完成后,执行宏任务队列
此时可能宏任务内有微任务,宏任务和主线程,都将其加入到自己对应的队列中
第二次循环结束
直接执行主线程,再将微任务队列全部清空后,执行宏任务对列,以此原则进行循环
直到所有队列全部为空,结束这个循环
再执行浏览器空闲状态下会执行的函数
结束
直接做题:
第一题
new Promise(resolve => {
console.log('promise');
resolve(5);
}).then(value=>{
console.log('then回调', value)
})
function func1() {
console.log('func1');
}
setTimeout(() => {
console.log('setTimeout');
});
func1();
解析:
看到new Promise,主线程,输出promise
resolve返回一个成功的结果等待then调用,无视不管
promise.then,微任务,加入到微任务队列 (微任务队列promise.then)
看到setTimeout(),宏任务,加入到宏任务队列(宏任务队列setTimeout)
执行主线程fun1(),输出 func1
没有主线程了,执行微任务,输出then回调 5
没有微任务了,执行宏任务,输出setTimeout
答案(我在node环境下输出的结果):
["c:\Users\asus\Desktop\advert\test.js" ] node
promise
func1
then回调 5
setTimeout
[0 in 0.109 seconds ] exited with code=
第二题
在做下面这道题之前需要先知道一个知识点
通过引入 queueMicrotask(),可以避免通过 promise 去创建微任务而带来的风险。举例来说,当使用 promise 创建微任务时,由回调抛出的异常被报告为 rejected promises 而不是标准异常。
不懂也没事,这玩意应该用不上,反正就把这个看成promise.then的函数 ,是个微任务就行
setTimeout(function () {
console.log("set1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});
new Promise(function (resolve) {
console.log("pr1");
resolve();
}).then(function () {
console.log("then1");
});
setTimeout(function () {
console.log("set2");
});
console.log(2);
queueMicrotask(() => {
console.log("queueMicrotask1")
});
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
});
解析:
因为很难表示队列里面的任务,所以我一般以队列里面即将要输出的标记这个任务
看到setTimeout,宏任务,加入队列(宏任务队列 set 1)
看到new Promise,主线程,直接输出 pr1
将promise.then ,微任务,加入到微任务队列(微任务队列,then1)
看到setTimeout,宏任务,加入队列(宏任务队列 set1 , set2)
看到console.log,主线程,直接输出 2
看到queue,微任务,加入队列(微任务队列,then1 , queue1)
看到new Promise ,主线程,没东西输出
将promise.then ,微任务,加入队列(微任务队列,then1 , queue1,then3)
从头到尾执行了一圈,然后开始执行微任务then1,输出then1
执行微任务queue,输出queueMicrotask1
执行微任务,then3,输出then3
微任务没了,执行宏任务set1
里面首先是console.log,主线程直接输出set1
new Promise, 主线程,没东西输出
promise.then,微线程,加入队列(微任务队列 then4)
console.log,主线程,输出then2
宏任务set1做完了,微任务多了个新的then4,执行,输出then4
执行宏任务set2,输出set2
答案(我在node环境下输出的结果):
["c:\Users\asus\Desktop\advert\test.js" ] node
pr1
2
then1
queueMicrotask1
then3
set1
then2
then4
set2
[0 in 0.158 seconds ] exited with code=
还有两个题目,解析写起来太耗时间了,今天晚上就先不写了,明天更。
其中有一题我是在某某阳光上面看到的,答案是错误的,如果有看过那篇文章的伙伴,可以期待明天我给出的正确答案。
希望大家多多点赞,分享,转发