本文目录导读:

- setTimeout / setInterval
- Promise 和微任务
- requestAnimationFrame
- Web Workers
- 异步迭代器和生成器
- 使用异步函数包装
- 自定义事件队列
- 关键概念解释
- 实际应用示例
在JavaScript中,异步执行事件回调函数有多种方式,我来介绍几种主要的实现方法:
setTimeout / setInterval
将回调延迟到事件循环的下一个tick执行:
element.addEventListener('click', function(event) {
setTimeout(() => {
// 异步执行的回调
console.log('异步执行,不阻塞其他事件');
}, 0);
});
Promise 和微任务
使用Promise或queueMicrotask创建微任务:
element.addEventListener('click', function(event) {
Promise.resolve().then(() => {
// 微任务,比setTimeout更早执行
console.log('作为微任务异步执行');
});
// 或者使用queueMicrotask
queueMicrotask(() => {
console.log('微任务方式');
});
});
requestAnimationFrame
适合动画相关的异步执行:
element.addEventListener('scroll', function(event) {
// 使用requestAnimationFrame节流
if (!this.rafId) {
this.rafId = requestAnimationFrame(() => {
// 在下一帧执行
console.log('在下一帧执行');
this.rafId = null;
});
}
});
Web Workers
真正的并行执行(不能访问DOM):
// 主线程
const worker = new Worker('worker.js');
element.addEventListener('click', function() {
worker.postMessage({type: 'process'});
});
// worker.js
self.addEventListener('message', function(e) {
// 在独立线程中执行
const result = heavyComputation();
self.postMessage(result);
});
异步迭代器和生成器
element.addEventListener('click', async function(event) {
const asyncGenerator = async function*() {
yield await someAsyncOperation();
yield await anotherAsyncOperation();
};
for await (const result of asyncGenerator()) {
console.log(result);
}
});
使用异步函数包装
element.addEventListener('click', async function(event) {
event.preventDefault(); // 立即执行
// 异步执行
const data = await fetchData();
processData(data);
});
自定义事件队列
class AsyncEventQueue {
constructor() {
this.queue = [];
this.processing = false;
}
enqueue(callback) {
this.queue.push(callback);
if (!this.processing) {
this.processQueue();
}
}
async processQueue() {
this.processing = true;
while (this.queue.length) {
const callback = this.queue.shift();
await new Promise(resolve => {
// 异步执行回调
setTimeout(() => {
callback();
resolve();
}, 0);
});
}
this.processing = false;
}
}
const eventQueue = new AsyncEventQueue();
element.addEventListener('click', function(event) {
// 将回调加入异步队列
eventQueue.enqueue(() => {
// 这里是异步执行的回调
console.log('按顺序异步执行');
});
});
关键概念解释
| 方法 | 执行时机 | 是否阻塞 | 适用场景 |
|---|---|---|---|
setTimeout(fn, 0) |
下一个宏任务 | 否 | 通用异步执行 |
Promise.resolve().then() |
微任务 | 否 | 需要尽快执行 |
requestAnimationFrame |
下一帧渲染前 | 否 | 动画、UI更新 |
| Web Workers | 独立线程 | 否 | 繁重计算 |
实际应用示例
// 防抖+异步执行
function debounceAsync(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
return new Promise(resolve => {
timeout = setTimeout(async () => {
const result = await func.apply(this, args);
resolve(result);
}, wait);
});
};
}
// 使用
const asyncHandler = debounceAsync(async (event) => {
const response = await fetch('/api/data');
const data = await response.json();
console.log('异步处理结果:', data);
}, 300);
element.addEventListener('input', asyncHandler);
选择哪种方式取决于你的具体需求:
- 不阻塞UI:使用
setTimeout或Promise - 需要最新帧数据:使用
requestAnimationFrame - CPU密集型任务:使用 Web Workers
- 需要按顺序执行:使用事件队列