脚本如何异步执行事件回调函数

wen 实用脚本 26

本文目录导读:

脚本如何异步执行事件回调函数

  1. setTimeout / setInterval
  2. Promise 和微任务
  3. requestAnimationFrame
  4. Web Workers
  5. 异步迭代器和生成器
  6. 使用异步函数包装
  7. 自定义事件队列
  8. 关键概念解释
  9. 实际应用示例

在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:使用 setTimeoutPromise
  • 需要最新帧数据:使用 requestAnimationFrame
  • CPU密集型任务:使用 Web Workers
  • 需要按顺序执行:使用事件队列

抱歉,评论功能暂时关闭!