宏任务与微任务
浏览器为了能够使得 JS 内部 task(任务) 与 DOM 任务能够有序的执行,会在一个 task 执行结束后,在下一个 task 执行开始前,对页面进行重新渲染 (task-> 渲染-> task->…)
宏任务(task):就是JS 内部(任务队列里)的任务,严格按照时间顺序压栈和执行。如 setTimeOut、setInverter、setImmediate 、 MessageChannel等
微任务(Microtask ):通常来说就是需要在当前 task 执行结束后立即执行的任务,例如需要对一系列的任务做出回应,或者是需要异步的执行任务而又不需要分配一个新的 task,这样便可以减小一点性能的开销。microtask 队列是一个与 task 队列相互独立的队列,microtask 将会在每一个 task 执行结束之后执行。每一个 task 中产生的 microtask 都将会添加到 microtask 队列中,将会添加至当前 microtask 队列的尾部,并且 microtask 会按序的处理完队列中的所有任务,然后开始执行下一个 task 。microtask 类型的任务目前包括了 MutationObserver 以及 Promise 的回调函数。
console.log("start");
Promise.resolve().then(function(){
console.log("promise1(微)")
})
setTimeout(function(){
console.log("setTimeout(宏)")
},0);
Promise.resolve().then(function(){
console.log("promise2(微)")
})
console.log("end");
//输出
//start
//end
//promise1(微)
//promise2(微)
//setTimeout(宏)
(1)当前 JS 代码进入主线程被 JS 引擎执行,当前是一个宏任务。按序执行,先输出 start
(2) 接着执行 Promise.resolve(1),该回调进入微任务
(3)执行 setTimeout,回调进入宏任务(这个宏任务是下一个宏任务,而不是当前宏任务)
(4)执行Promise.resolve(2),该回调进入微任务
(5)继续执行,输出end,当前宏任务执行完毕。检测微任务列表
(6)执行微任务列表,按顺序输出 promise1(微) promise2(微)
(7)当前微任务列表为空,渲染 DOM 后执行下一宏任务,即 setTimeout 回调函数,输出 setTimeout(宏)
总的来说:就是先执行宏任务中的主线程(如果不了解线程,本人博客中有介绍,当然大佬们就不需要看咯)碰到宏任务、微任务先放一边。执行完主线程,再执行微任务 执行完后开始执行下一个宏任务 以此类推
!!!注意 一定要注意执行宏任务的先后顺序
再举个例子 测试一下 不要先看输出结果哦
console.log("start");
setTimeout(function(){
console.log("setTimeout1(宏)");
setTimeout(function(){
Promise.resolve().then(function(){
console.log("promise3(微)");
})
console.log("setTimeout4(宏)");
},0);
Promise.resolve().then(function(){
console.log("promise2(微)");
})
console.log("next");
},0);
Promise.resolve().then(function(){
console.log("promise1(微)");
setTimeout(function(){
console.log("setTimeout3(宏)");
},0);
})
setTimeout(function(){
console.log("setTimeout2(宏)");
},0);
console.log("end");
//输出结果
// start
// end
// promise1(微)
// setTimeout1(宏)
// next
// promise2(微)
// setTimeout2(宏)
// setTimeout3(宏)
// setTimeout4(宏)
// promise3(微)