由于js是单线程的,容易造成阻塞,为了解决这个问题,引出了两个概念,同步和异步。我们都知道 Js 是单线程的,但是一些高耗时操作就带来了进程阻塞问题。为了解决这个问题,Js 有两种任务的执行模式:同步模式(Synchronous)和异步模式(Asynchronous)。
在异步模式下,创建异步任务主要分为宏任务与微任务两种。ES6 规范中,宏任务(Macrotask) 称为 Task, 微任务(Microtask) 称为 Jobs。宏任务是由宿主(浏览器、Node)发起的,而微任务由 JS 自身发起。
宏任务与微任务的几种创建方式 👇
宏任务(Macrotask) | 微任务(Microtask) |
---|---|
setTimeout | requestAnimationFrame(有争议) |
setInterval | MutationObserver(浏览器环境) |
MessageChannel | Promise.[ then/catch/finally ] |
I/O,事件队列 | process.nextTick(Node环境) |
setImmediate(Node环境) | queueMicrotask |
script(整体代码块) |
如何理解 script(整体代码块)是个宏任务呢 🤔
实际上如果同时存在两个 script 代码块,会首先在执行第一个 script 代码块中的同步代码,如果这个过程中创建了微任务并进入了微任务队列,第一个 script 同步代码执行完之后,会首先去清空微任务队列,再去开启第二个 script 代码块的执行。所以这里应该就可以理解 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 () {//微任务放入微队列
console.log('10');
})
new Promise(function (resolve) { //同步代码
console.log('11');
resolve();
}).then(function () {//微任务放入微队列
console.log('12')
})
})
打印结果为: 1,7,6,8,2,4,3,5,9,11,10,12