web Worker

56 阅读3分钟

Web Worker 是一种在浏览器中运行 JavaScript 的方式,允许你将计算密集型任务或耗时操作(比如数据处理、文件操作等)放到独立的线程中执行,从而避免阻塞主线程的 UI 渲染和用户交互。

为什么使用 Web Worker?

在 JavaScript 中,代码通常是在主线程上执行的,这样一来,复杂的计算或者异步操作可能会导致页面卡顿,影响用户体验。Web Worker 允许你将这些任务移到一个后台线程,主线程可以继续进行页面渲染、处理用户输入等操作。

Web Worker 的基本用法

  1. 创建 Worker: 创建 Worker 时,通常会传入一个包含 Worker 代码的 JavaScript 文件,或者使用内联代码(即将代码作为字符串传递给 Worker)。

    使用外部脚本:

        // 创建一个 Worker 实例
        const worker = new Worker('worker.js');
    
        // 向 Worker 发送消息
        worker.postMessage('Hello, Worker!');
    
        // 接收 Worker 发来的消息
        worker.onmessage = function (e) {
          console.log('来自 Worker 的消息:', e.data);
        };
    
        ```
        `worker.js` 内容:
        ```javascript
        // Worker 中的代码 
        onmessage = function (e) { 
            console.log('接收到主线程消息:', e.data); 
            postMessage('Hello, Main Thread!'); 
        };
    
  2. 使用内联代码: 如果你不想创建单独的文件,可以通过 BlobURL.createObjectURL() 创建内联 Worker。

        const blob = new Blob([`
          onmessage = function(e) {
            postMessage('Hello from Inline Worker!');
          }
        `], { type: 'application/javascript' });
    
        const worker = new Worker(URL.createObjectURL(blob));
    
        worker.onmessage = function (e) {
          console.log(e.data); // 输出: Hello from Inline Worker!
        };
    
        worker.postMessage('start');
    
  3. 与 Worker 通信

    • 主线程通过 postMessage() 向 Worker 发送数据。
    • Worker 也使用 postMessage() 向主线程发送数据。
    • 使用 onmessage 监听接收到的数据。
  4. 停止 Worker

    • 主线程可以通过 terminate() 强制停止 Worker,但 Worker 无法处理这一事件。
    • 在 Worker 内部,可以通过 close() 方法停止自己。
    // 停止 Worker
    worker.terminate();
    

    在 Worker 内部:

    // 在 Worker 中停止自己
    close();
    

Web Worker 的特点

  • 多线程:Web Worker 运行在一个独立的线程中,不会阻塞主线程的执行。
  • 异步通信:主线程与 Worker 之间通过异步消息传递进行通信(postMessageonmessage)。
  • 隔离:Worker 中的代码是完全独立的,它无法访问主线程的 DOM 和全局变量,只能通过消息通信与主线程交互。

使用 Web Worker 时的注意事项:

  1. 无法访问 DOM:Worker 中无法访问或修改页面的 DOM 元素,它只能执行计算任务或者处理数据。
  2. 性能开销:创建 Worker 会有一定的性能开销,特别是在频繁创建和销毁 Worker 的情况下,因此应该权衡是否真的需要使用 Worker。
  3. 支持的浏览器:几乎所有现代浏览器都支持 Web Worker,但某些特性(如共享工作线程 SharedWorker)可能在不同的浏览器中支持情况有所不同。

示例:使用 Web Worker 进行耗时任务

例如,计算一个大数组的和,我们可以将这项任务放到 Worker 中来避免阻塞主线程:

// 创建 Worker
const worker = new Worker('sumWorker.js');

// 向 Worker 发送数据
worker.postMessage([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

// 接收 Worker 计算结果
worker.onmessage = function(e) {
  console.log('总和是:', e.data);  // 输出:总和是: 55
};

// sumWorker.js 内容
onmessage = function(e) {
  const data = e.data;
  const sum = data.reduce((acc, curr) => acc + curr, 0);
  postMessage(sum);
};

这样,计算大数组的和会被分配给 Worker,而主线程则可以继续处理其他任务,比如更新 UI 或处理用户交互。