javaScript 同时执行多个任务方案

javaScript 同时执行多个任务方案

在 JavaScript 中,如果需要同时执行多个任务,选择合适的方式取决于任务的性质、执行环境以及对性能和资源的需求。以下是几种常见的方式及其优缺点:


1. setTimeout

  • 适用场景:简单的异步任务,任务之间没有强依赖关系。

  • 优点

    • 实现简单,代码易于理解。
    • 不会阻塞主线程,适合轻量级任务。
  • 缺点

    • 精度较低,setTimeout​ 的最小延迟为 4ms(在现代浏览器中)。
    • 不适合需要高精度或长时间运行的任务。
    • 无法充分利用多核 CPU。

示例:

setTimeout(() => {
    console.log('Task 1');
}, 0);

setTimeout(() => {
    console.log('Task 2');
}, 0);

2. Promise

  • 适用场景:异步任务,任务之间有依赖关系或需要顺序执行。

  • 优点

    • 支持链式调用,代码结构清晰。
    • 可以与 async/await​ 结合,简化异步代码。
    • 适合处理需要顺序执行的任务。
  • 缺点

    • 仍然是单线程执行,不适合长时间运行的计算任务。
    • 如果任务较多,可能会阻塞主线程。

示例:

Promise.all([
    new Promise(resolve => {
        setTimeout(() => {
            console.log('Task 1');
            resolve();
        }, 1000);
    }),
    new Promise(resolve => {
        setTimeout(() => {
            console.log('Task 2');
            resolve();
        }, 1000);
    })
]).then(() => {
    console.log('All tasks completed');
});

3. Worker

  • 适用场景:需要长时间运行的计算任务,或者需要充分利用多核 CPU 的场景。

  • 优点

    • 在单独的线程中运行,不会阻塞主线程。
    • 适合 CPU 密集型任务(如图像处理、数据计算等)。
    • 可以充分利用多核 CPU。
  • 缺点

    • 实现稍微复杂,需要处理线程间通信。
    • 不适合轻量级任务,因为创建线程本身会有开销。
    • 无法直接访问主线程的 DOM 和全局变量。

示例:

// 主线程
const worker1 = new Worker('worker1.js');
const worker2 = new Worker('worker2.js');

worker1.onmessage = (event) => {
    console.log('Task 1 result:', event.data);
};

worker2.onmessage = (event) => {
    console.log('Task 2 result:', event.data);
};

worker1.postMessage('start');
worker2.postMessage('start');

// worker1.js
self.onmessage = (event) => {
    if (event.data === 'start') {
        // 模拟长时间运行的任务
        let result = 0;
        for (let i = 0; i < 1e9; i++) {
            result += i;
        }
        self.postMessage(result);
    }
};

4. WebAssembly+ Worker

  • 适用场景:需要高性能计算的任务,尤其是涉及大量数学运算或复杂逻辑的场景。

  • 优点

    • 提供接近原生性能的计算能力。
    • 可以与 Worker​ 结合,避免阻塞主线程。
  • 缺点

    • 实现复杂,需要编写或编译 C/C++ 代码。
    • 不适合轻量级任务。

示例:

// 主线程
const worker = new Worker('wasmWorker.js');

worker.onmessage = (event) => {
    console.log('Wasm result:', event.data);
};

worker.postMessage('start');

// wasmWorker.js
importScripts('wasmModule.js'); // 假设 wasmModule.js 是 WebAssembly 模块

self.onmessage = (event) => {
    if (event.data === 'start') {
        const result = wasmModule.compute(); // 调用 WebAssembly 函数
        self.postMessage(result);
    }
};

5. requestIdleCallback

  • 适用场景:需要在浏览器空闲时执行的任务,适合轻量级任务。

  • 优点

    • 不会阻塞主线程,适合在浏览器空闲时执行任务。
    • 节省资源,避免不必要的性能开销。
  • 缺点

    • 任务执行时间不可控,可能会被延迟。
    • 不适合需要立即执行的任务。

示例:

requestIdleCallback(() => {
    console.log('Task 1');
});

requestIdleCallback(() => {
    console.log('Task 2');
});

总结与推荐:

方式 适用场景 优点 缺点 推荐指数
setTimeout 轻量级异步任务 简单易用,不阻塞主线程 精度低,不适合长时间任务 ⭐⭐
Promise 异步任务,任务间有依赖关系 代码结构清晰,支持链式调用 单线程执行,不适合长时间任务 ⭐⭐⭐
Worker 长时间运行任务,CPU 密集型任务 不阻塞主线程,充分利用多核 CPU 实现复杂,线程间通信开销 ⭐⭐⭐⭐
WebAssembly + Worker 高性能计算任务 接近原生性能,结合 Worker 避免阻塞主线程 实现复杂,需要编写或编译 C/C++ 代码 ⭐⭐⭐⭐⭐
requestIdleCallback 浏览器空闲时执行的轻量级任务 节省资源,避免不必要的性能开销 任务执行时间不可控,不适合立即执行的任务 ⭐⭐
  • 轻量级任务:推荐使用 setTimeout​ 或 requestIdleCallback​。
  • 异步任务:推荐使用 Promise​ 或 async/await​。
  • 长时间运行任务:推荐使用 Worker​。
  • 高性能计算任务:推荐使用 WebAssembly + Worker​。

image.png

留下你的脚步
推荐阅读