queueMicrotask
#bom
#异步
目录
1. 基本概念
// 最简单的使用方式
queueMicrotask(() => {
console.log('这是一个微任务');
});
queueMicrotask
是一个用于将回调函数作为微任务(microtask) 添加到微任务队列中的全局函数- nodejs 环境和浏览器环境都可用
queueMicrotask
可用于批量处理状态更新- 确保 DOM 只更新一次,而不是每次状态变化都更新,如下代码
let state = { count: 0 };
let updateScheduled = false;
function updateState(newState) {
Object.assign(state, newState);
if (!updateScheduled) {
updateScheduled = true;
queueMicrotask(() => {
updateDOM();
updateScheduled = false;
});
}
}
function updateDOM() {
console.log("Updating DOM with state:", state);
// 实际的 DOM 更新操作
}
// 使用示例
updateState({ count: 1 });
updateState({ count: 2 });
updateState({ count: 3 });
console.log("Current state:", state);
2. 与 Promise 的关系
看哪个在前面,哪个在前面就先执行
// 这两种方式效果相同
queueMicrotask(() => {
console.log('方式1');
});
Promise.resolve().then(() => {
console.log('方式2');
});
3. 执行顺序
console.log('1'); // 同步任务
setTimeout(() => {
console.log('4'); // 宏任务
}, 0);
queueMicrotask(() => {
console.log('2'); // 微任务
});
console.log('3');
// 输出顺序: 1, 3, 2, 4
4. 常见使用场景及注意事项
4.1. 状态同步
class State {
constructor() {
this.value = 0;
this.callbacks = [];
}
setValue(newValue) {
this.value = newValue;
// 确保回调在当前同步代码执行完后才执行
queueMicrotask(() => {
this.callbacks.forEach(cb => cb(this.value));
});
}
onChange(callback) {
this.callbacks.push(callback);
}
}
4.2. 防止递归嵌套堆栈溢出
function processArray(array) {
const results = [];
function process(index) {
if (index >= array.length) return;
results.push(array[index]);
// 避免深层递归
queueMicrotask(() => process(index + 1));
}
process(0);
}
4.3. 错误处理:一定要==顶层使用==
// 错误的方式
try {
queueMicrotask(() => {
throw new Error('错误');
});
} catch(e) {
// 永远不会捕获到错误
console.error(e);
}
// 正确的方式
queueMicrotask(() => {
try {
throw new Error('错误');
} catch(e) {
console.error(e);
}
});
4.4. 批量处理
class BatchProcessor {
constructor() {
this.queue = [];
this.scheduled = false;
}
add(item) {
this.queue.push(item);
if (!this.scheduled) {
this.scheduled = true;
queueMicrotask(() => {
this.processQueue();
this.scheduled = false;
});
}
}
processQueue() {
const items = [...this.queue];
this.queue = [];
// 处理队列项
items.forEach(item => console.log('处理:', item));
}
}
4.5. 尽量顶层使用
// 不好的做法
for (let i = 0; i < 1000; i++) {
queueMicrotask(() => console.log(i));
}
// 更好的做法
const items = Array.from({length: 1000}, (_, i) => i);
queueMicrotask(() => {
items.forEach(i => console.log(i));
});
5. 与其他异步机制的比较
// 1. queueMicrotask
queueMicrotask(() => console.log('微任务'));
// 2. Promise
Promise.resolve().then(() => console.log('Promise微任务'));
// 3. setTimeout
setTimeout(() => console.log('宏任务'), 0);
// 4. requestAnimationFrame
requestAnimationFrame(() => console.log('动画帧'));
// 执行顺序:微任务 ≈ Promise微任务 > 宏任务 > 动画帧
6. 总结
queueMicrotask
是处理微任务的标准方式- 比
Promise
更直接和轻量 - 适用于需要异步但又要保持高优先级的场景
- 需要注意错误处理和性能影响