浏览器event loop 事件循环
浏览器线程
浏览器是多进程的,包含Browser Process (管理浏览器tab等)、Render Process 渲染进程还有其他的进程,Render Process分为主线程,js引擎和 ui渲染线程
宏任务
宏任务 也称为 macrotask、tasks
以下异步任务的回调会进入到MacrotaskQueue宏任务队列,包含
setTimeOutsetIntevalsetImmediate[Node环境]requestAnimationFrame[浏览器环境]I/OUi rednder[浏览器环境]
执行顺序:ui rednder>requestAnimationFrame>setTimeOut>setInteval>setImmediate
I/O操作一般是耗时的,所以看返回的时机插入在谁后面执行,和定时的一样。
微任务
微任务 也称为 microtask、jobs
以下异步任务的回调会进入到MacrotaskQueue微任务队列,包含
Process.nextTick[Node环境]Promise.then()Object.observerMutationObserver[浏览器环境]
执行顺序:Process.nextTick>Promise>MutationObserver
注意:Promise构造函数内的代码是同步执行的
浏览器端的事件循环机制
执行栈(调用栈)js stack、事件队列(宏任务队列)tasks、Marotask Queue、微任务队列Mirotask Queue
每次事件循环先从事件队列中取事件执行,其中有微任务,就放在微任务队列中,本次事件执行结束前去检查微任务队列,然后执行微任务队列中的方法,执行完成后结束本次循环。然后进行下次循环。
猜测
setTimeOut和setInteval是计时排序执行,定时线程计时完成后推到事件任务队列中,I/O应该也是一样的
例子:
console.log("1");
setTimeout(function () {
console.log("2");
new Promise(function (resolve) {
console.log("3");
resolve();
}).then(function () {
console.log("4");
});
});
new Promise(function (resolve) {
console.log("5");
resolve();
}).then(function () {
console.log("6");
new Promise(function (resolve) {
console.log("7");
resolve();
}).then(function () {
console.log("8");
});
setTimeout(function () {
console.log("9");
});
});
new Promise(function (resolve) {
console.log("10");
resolve();
}).then(function () {
console.log("11");
});
setTimeout(function () {
console.log("12");
new Promise(function (resolve) {
console.log("13");
resolve();
}).then(function () {
console.log("14");
});
}, 5);
setImmediate(() => {
console.log("15");
});
setTimeout(function () {
console.log("16");
}, 3);
setTimeout(function () {
console.log("17");
}, 10);
输出结果:1 5 10 6 7 11 8 2 3 4 15 9 16 12 13 14 17
结果解析:
第一次循环 1 5 10 6 7 11 8
第二次循环 2 3 4
第三次循环 15
第四次循环 9
第五次循环 16
第六次循环 12 13 14
第七次循环 17
相当于是每2个宏任务的间隙去执行微任务