JavaScript 引擎在执行任务时,有两种类型的任务:宏任务(macro task)和微任务(micro task)。它们之间的差别在于执行顺序和触发方式,因此理解它们的区别很重要,也有助于我们编写更高效、优雅的代码。
什么是宏任务和微任务?
在 JavaScript 中,宏任务可以理解为当前执行栈中的任务,例如 script(整体代码)、setTimeout、setInterval、setImmediate、I/O、UI 等事件。当执行栈中的任务执行完毕后,JavaScript 引擎会立即从任务队列中取出一个宏任务执行。
而微任务则是在同一个执行栈中的任务(script 后)、Promise 的回调函数和 DOM 变化事件(例如:input 事件、scroll 事件等)。
需要注意的是,虽然它们在调用顺序上有区别,但它们的本质都是把代码的执行结果放到对应的任务队列中去等待 JavaScript 引擎的执行。
如何操作宏任务和微任务?
在 JavaScript 中,我们通过内置的函数可以很方便地在宏任务和微任务之间进行操作。
操作宏任务
- setTimeout/setInterval
在 JavaScript 中,可以通过 setTimeout 和 setInterval 来操作宏任务队列。它们都接受两个参数:第一个参数是要执行的函数,第二个参数是时间(毫秒),表示在多长时间之后执行函数。
例如,在 2 秒之后输出一个字符串:
setTimeout(function() {
console.log('2 秒后输出!');
}, 2000);
- setImmediate
在 Node.js 中,可以使用 setImmediate 来添加一个宏任务到队列中。与 setTimeout 不同的是,setImmediate 总是在当前队列的尾部,也就是下一个宏任务之前执行。
setImmediate(function() {
console.log('当前任务执行完后立即输出!');
});
操作微任务
- Promise
在 JavaScript 中,可以使用 Promise 对象来操作微任务队列。Promise 构造器接收一个函数 argument,它会立即执行,而在该 constructor 内部调用 resolve/reject 则会把对应的 callback 交给微任务队列处理。
例如,在 Promise 中,无论 fulfill 还是 reject 都被认为是一种微任务:
Promise.resolve().then(function() {
console.log('在 Promise 中输出!');
});
- MutationObserver
除了 Promise 以外,MutationObserver 也能添加一个微任务到队列中。MutationObserver 提供了一种异步回调解决 liuon 等 DOM 变化问题的简便方法。
例如,在 MutationObserver 中,无论 type 是什么,都会触发一个微任务:
var observer = new MutationObserver(function(mutations) {
console.log('触发 MutationObserver 了!');
});
observer.observe(document, { attributes: true, childList: true, subtree: true });
题外话
在实际开发中,宏任务和微任务的操作常常被忽略,甚至有开发者直接把 Promise 当做同步操作来使用,这是不正确的。
在开发时,我们需要注意一些细节,比如:Promise 在一个执行栈中最多执行一个 then 。在 Promise 中使用一些 async/await 等语法时,也需要注意它们所产生的微任务,否则可能会出现一些难以排查的 bug。
在实践中,正确地操作宏任务和微任务可以提高代码的性能和可维护性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript 操作宏任务与微任务 - Python技术站