1. 你了解浏览器中的事件循环机制(Event Loop)吗?
1.1 为什么js在浏览器中有事件循环机制?
js是单线程语言,为了解决各类浏览器事件同时触发时,如何排队依次执行,就需要事件循环机制。
1.2 事件循环中的两种任务:
- 宏任务(Task Queue):js代码执行,`setTimeout`,`setInterval`, I/O操作
- 微任务(Microtask Queue):`new Promise().then`, `MutaionObserver`
1.3 为什么要引入微任务的概念,只有宏任务可以吗?
调整浏览器事件的优先级,可以让紧急任务快速响应,提高用户使用体验。
1.4 浏览器中的事件循环过程:
- 从宏任务队列中取出一个可执行任务,如果有则执行,没有下一步。
- 挨个取出微任务队列中的所有任务执行,执行完毕或没有则下一步。
- 浏览器渲染。
1.5 Node中的事件循环和浏览器中的有什么区别?
-
Node中的宏任务执行顺序:
- timers定时器:执行已经安排的
setTimeout和setInterval的回调函数 - pending callback 待定回调:执行延迟到下一个循环迭代的I/O回调
- idle,prepare:仅系统内部使用
- poll:检索新的I/O事件,执行与I/O相关的回调
- close callbacks
- timers定时器:执行已经安排的
-
Node中的事件循环:
- Node v10及以前:
- 执行完一个阶段中的所有任务
- 执行nextTick队列里的内容
- 执行完微任务队列的内容
- Node v10以后:和浏览器的事件循环机制一样
- Node v10及以前:
1.6 看代码写输出:
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');
运行结果:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
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) => {
console.log('children7');
setTimeout(() => {
console.log(res);
}, 0);
});
运行结果:
start
children4
children2
children3
children5
children7
children6
1.8 看代码写输出:
const p = function () {
return new Promise((resolve, reject) => {
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 0);
resolve(2);
});
p1.then((res) => {
console.log(res);
});
console.log(3);
resolve(4);
})
};
p().then((res) => {
console.log(res);
});
console.log('end');
运行结果:
3
end
2
4