Blog
Blog copied to clipboard
执行机制 - 宏任务和微任务分别有哪些
宏任务和微任务分别有哪些
为何区分宏任务和微任务
确保一致的执行顺序
假设有以下代码,对请求结果作缓存:
let data
function getData() {
if (data) {
console.log('loaded data')
} else {
ajax().then(data => {
console.log('loaded data')
})
}
}
这样实现带来的问题是在有缓存和无缓存的情况下,执行顺序会出现不一致的情况:
console.log('get data start')
getData()
console.log('get data end')
上方代码在无缓存时调用,打印顺序为get data start
-> get data end
-> loaded data
有缓存时调用,打印顺序为get data start
-> loaded data
-> get data end
如果这些打印操作变为数据修改操作,就可能导致意料之外的情况发生,所以我们可以使用微任务来确保一致的执行顺序:
function getData() {
if (data) {
window.queueMicrotask(() => {
console.log('loaded data')
})
} else {
ajax().then(data => {
console.log('loaded data')
})
}
}
这样无论有无缓存,打印顺序都为get data start
-> get data end
-> loaded data
。
批量操作
将批量操作统一处理,避免多次调用的开销。
下面的代码片段演示了如何对多个消息进行处理:通过一个微任务在当前宏任务退出时将这些消息作为单一的对象发送出去。
const messageQueue = []
let sendMessage = message => {
messageQueue.push(message)
if (messageQueue.length === 1) {
queueMicrotask(() => {
const json = JSON.stringify(messageQueue)
messageQueue.length = 0
fetch('url-of-receiver', json)
})
}
}
时效性
上面提到的两个场景大家可能认为可以使用setTimeout
替代,但有一个容易忽略的点是,假设上述任务执行时,任务队列中有宏任务等待执行,且宏任务改变了数据或阻塞线程时间过长,此时若使用setTimeout
实现,可能会和预期表现有出入。
所以在有数据时效性要求的场景下,使用微任务可以确保当前任务执行完后执行,例如实时数据分析等。
宏任务有哪些
-
<script>
标签中的运行代码 - 事件触发的回调函数,例如
DOM Events
、I/O
、requestAnimationFrame
-
setTimeout
、setInterval
的回调函数