js中的宏任务和微任务

一、初识宏任务和微任务

在JavaScript中,有两类异步任务队列:宏任务队列(macrotasks)和微任务队列(microtasks)。宏任务队列可以有多个,微任务队列只有一个。

1、宏任务(macrotasks):就是JS 内部(任务队列里)的任务,严格按照时间顺序压栈和执行。如: script(全局任务)、setTimeout、setInterval、setImmediate、I/O、UI rendering 、 MessageChannel等。

2、微任务(Microtask ):通常来说就是需要在当前 任务 执行结束后立即执行的任务。如: process.nextTick (node.js中进程相关的对象)、Promise、Async/Await(实际就是promise)、Object.observer、MutationObserver。

在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。

只需记住当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。

运行机制:
(1)在执行栈中执行一个宏任务。
(2)执行过程中遇到微任务,将微任务添加到微任务队列中。
(3)当前宏任务执行完毕,立即执行微任务队列中的任务。
(4)当前微任务队列中的任务执行完毕,检查渲染,GUI线程接管渲染。
(5)渲染完毕后,js线程接管,开启下一次事件循环,执行下一次宏任务(事件队列中取)。

二、宏任务和微任务使用案例

<script>
//主线程直接执行
console.log('1');

setTimeout(function ()
console.log('2');
process.nextTick(function ()
console.log('3');
})

new Promise(function (resolve)
console.log('4');
resolve();
}).then(function ()
console.log('5')
})
})

process.nextTick(function ()
console.log('6');
})

new Promise(function (resolve){
console.log('7');
resolve();
}).then(function ()

console.log('8')
})

//丢到宏事件队列中
setTimeout(function ()
console.log('9');
process.nextTick(function ()
con5o1e.1og('10");
})

new Promise(function (resolve){
console.log('11');
resolve();
}).then(function ()
console.log('12')
})
})

console.log("13");

//执行输出结果:1,7,13,6,8,2,4,3,5,9,11,10,12
</script>

 案例分析:

(1)首先浏览器执行js进入第一个宏任务进入主线程, 直接打印console.log(‘1’)
(2)遇到 setTimeout 分发到宏任务Event Queue中
(3)遇到 process.nextTick 丢到微任务Event Queue中
(4)遇到 Promise, new Promise 直接执行 输出 7,13;
(5)执行then 被分发到微任务Event Queue中``
(6)第一轮宏任务执行结束,开始执行微任务 打印 6,8
(7)第一轮微任务执行完毕,执行第二轮宏事件,执行setTimeout
(8)先执行主线程宏任务,在执行微任务,打印’2,4,3,5’
(9)在执行第二个setTimeout,同理打印 ‘9,11,10,12’
(10)整段代码,共进行了三次事件循环,完整的输出为1,7,13,6,8,2,4,3,5,9,11,10,12

 

三、总结

(1)先是 宏任务–>微任务–>宏任务–>微任务 一直循环下去。值得注意的是队列的优先级执行顺序为: 先执行同步和立即执行任务>微任务>宏任务,即同一层级上微任务在宏任务之前执行。
(2)script代码为第一层宏任务,如果有setTimeout,setInterval,则他们的回调函数会成为第二层的宏任务。
(3)promise.then()和process.nextTick()是微任务,在执行完该一层的宏任务后执行,且process.nextTick()优先于promise.then()。
(4)JS引擎首先从macrotask queue中取出第一个任务,执行完毕后,将microtask queue中的所有任务取出,按顺序全部执行;
  然后再从macrotask queue(宏任务队列)中取下一个,执行完毕后,再次将microtask queue(微任务队列)中的全部取出;
  循环往复,直到两个queue中的任务都取完。

 

posted @ 2023-05-30 22:38  CodeFan*  阅读(1364)  评论(0编辑  收藏  举报