三门峡市护送服务网

JS中Worker相关知识点及用法详细解读

2026-04-23 20:46:01 浏览次数:0
详细信息

JavaScript Worker 相关知识点及用法详细解读

一、Worker 概述

1.1 什么是 Web Worker

Web Worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。它们可以在独立的线程中执行任务,避免阻塞主线程。

1.2 主要特点

二、Worker 类型

2.1 专用 Worker (Dedicated Worker)

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

// 只能被创建它的脚本使用
// 生命周期与创建它的页面绑定

2.2 共享 Worker (Shared Worker)

// 主线程 - 页面1
const worker = new SharedWorker('shared-worker.js');

// 主线程 - 页面2(同一域名下)
const worker2 = new SharedWorker('shared-worker.js');

// 多个页面可以共享同一个 Worker
// 通过 port 进行通信

2.3 Service Worker

// 主线程
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('service-worker.js')
    .then(registration => {
      console.log('Service Worker 注册成功:', registration);
    });
}

// 主要用于离线缓存、推送通知、后台同步等

三、基本用法

3.1 创建和使用 Worker

主线程代码 (main.js):

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

// 向 Worker 发送消息
worker.postMessage({
  type: 'CALCULATE',
  data: { numbers: [1, 2, 3, 4, 5] }
});

// 接收 Worker 的消息
worker.onmessage = function(event) {
  console.log('收到 Worker 消息:', event.data);

  if (event.data.type === 'RESULT') {
    console.log('计算结果:', event.data.result);
  }
};

// 错误处理
worker.onerror = function(error) {
  console.error('Worker 错误:', error);
};

// 终止 Worker
// worker.terminate();

Worker 线程代码 (worker.js):

// 接收主线程消息
self.onmessage = function(event) {
  const { type, data } = event.data;

  if (type === 'CALCULATE') {
    // 执行计算(不会阻塞主线程)
    const result = heavyCalculation(data.numbers);

    // 发送结果回主线程
    self.postMessage({
      type: 'RESULT',
      result: result
    });
  }
};

function heavyCalculation(numbers) {
  // 模拟耗时计算
  let sum = 0;
  for (let i = 0; i < numbers.length; i++) {
    sum += numbers[i];
    // 模拟复杂计算
    for (let j = 0; j < 1000000; j++) {
      // 密集计算
    }
  }
  return sum;
}

// 也可以使用 addEventListener
// self.addEventListener('message', handleMessage);

3.2 传递复杂数据

结构化克隆算法:

// Worker 支持传递大多数 JavaScript 类型
const complexData = {
  string: '文本',
  number: 123,
  boolean: true,
  array: [1, 2, 3],
  object: { key: 'value' },
  date: new Date(),
  map: new Map([['key', 'value']]),
  set: new Set([1, 2, 3]),
  typedArray: new Uint8Array([1, 2, 3]),
  blob: new Blob(['Hello World'], { type: 'text/plain' }),
  arrayBuffer: new ArrayBuffer(8)
};

// 但以下类型不能传递:
// - 函数
// - DOM 节点
// - 原型链
// - Error 和 Function 对象
// - 某些特定对象(如 Promise)

worker.postMessage(complexData);

Transferable Objects(可转移对象):

// 创建 ArrayBuffer
const buffer = new ArrayBuffer(1024 * 1024 * 10); // 10MB

// 使用可转移对象,避免复制大数据
worker.postMessage(
  { buffer: buffer },
  [buffer]  // 第二个参数指定可转移对象
);

// 注意:转移后,主线程不能再访问 buffer
// buffer.byteLength === 0

四、高级用法

4.1 动态创建 Worker

使用 Blob URL 创建内联 Worker:

// 将 Worker 代码作为字符串
const workerCode = `
  self.onmessage = function(e) {
    const result = e.data.num * 2;
    self.postMessage({ result: result });
  };
`;

// 创建 Blob
const blob = new Blob([workerCode], { type: 'application/javascript' });
const workerURL = URL.createObjectURL(blob);

// 创建 Worker
const worker = new Worker(workerURL);

// 使用后记得清理
worker.onmessage = function(e) {
  console.log('结果:', e.data.result);
  URL.revokeObjectURL(workerURL); // 清理 URL
};

4.2 模块化 Worker

ES6 模块支持:

// 主线程
const worker = new Worker('module-worker.js', {
  type: 'module'  // 指定为模块
});

// Worker 线程 (module-worker.js)
import { calculate } from './calculations.js';

self.onmessage = function(e) {
  const result = calculate(e.data);
  self.postMessage(result);
};

// 注意:需要服务器支持 CORS 和正确的 MIME 类型

4.3 Worker 中使用其他 Worker

// Worker 中也可以创建 Worker(子 Worker)
// worker.js
const subWorker = new Worker('sub-worker.js');

subWorker.onmessage = function(e) {
  // 处理子 Worker 的结果
  self.postMessage({
    type: 'FROM_SUB_WORKER',
    data: e.data
  });
};

self.onmessage = function(e) {
  // 将任务分配给子 Worker
  subWorker.postMessage(e.data);
};

五、共享 Worker

5.1 创建和连接共享 Worker

主线程代码:

// 创建或连接到共享 Worker
const worker = new SharedWorker('shared-worker.js');

// 通过 port 进行通信
worker.port.onmessage = function(event) {
  console.log('收到共享 Worker 消息:', event.data);
};

// 启动端口连接
worker.port.start();

// 发送消息
worker.port.postMessage({
  type: 'GREETING',
  message: 'Hello from page!'
});

// 断开连接
// worker.port.close();

共享 Worker 代码 (shared-worker.js):

// 存储所有连接的端口
const ports = [];

// 监听连接
self.onconnect = function(event) {
  const port = event.ports[0];
  ports.push(port);

  port.onmessage = function(event) {
    const message = event.data;

    // 广播消息给所有连接的端口
    if (message.type === 'BROADCAST') {
      ports.forEach(p => {
        if (p !== port) {
          p.postMessage({
            type: 'BROADCAST_MESSAGE',
            data: message.data,
            from: 'Shared Worker'
          });
        }
      });
    }

    // 响应特定消息
    port.postMessage({
      type: 'RESPONSE',
      data: 'Message received by Shared Worker'
    });
  };

  // 启动端口
  port.start();
};

5.2 共享 Worker 应用场景

六、Service Worker

6.1 注册和安装

主线程注册:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js')
      .then(function(registration) {
        console.log('ServiceWorker 注册成功: ', registration.scope);

        // 检查更新
        registration.addEventListener('updatefound', () => {
          console.log('发现新版本 Service Worker');
        });
      })
      .catch(function(err) {
        console.log('ServiceWorker 注册失败: ', err);
      });
  });
}

Service Worker 代码 (service-worker.js):

// 定义缓存名称
const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [
  '/',
  '/styles/main.css',
  '/script/main.js'
];

// 安装阶段
self.addEventListener('install', function(event) {
  // 跳过等待,立即激活
  // self.skipWaiting();

  // 缓存资源
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('已打开缓存');
        return cache.addAll(urlsToCache);
      })
  );
});

// 激活阶段
self.addEventListener('activate', function(event) {
  // 清理旧缓存
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheName !== CACHE_NAME) {
            console.log('删除旧缓存:', cacheName);
            return caches.delete(cacheName);
          }
        })
      );
    })
  );

  // 立即控制所有客户端
  // event.waitUntil(self.clients.claim());
});

// 拦截请求
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // 缓存命中
        if (response) {
          return response;
        }

        // 克隆请求(因为请求是流,只能使用一次)
        const fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(
          function(response) {
            // 检查响应是否有效
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // 克隆响应(因为响应是流,只能使用一次)
            const responseToCache = response.clone();

            // 缓存新资源
            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
  );
});

// 推送通知
self.addEventListener('push', function(event) {
  const title = '推送通知标题';
  const options = {
    body: '推送通知内容',
    icon: '/images/icon.png',
    badge: '/images/badge.png'
  };

  event.waitUntil(
    self.registration.showNotification(title, options)
  );
});

// 通知点击
self.addEventListener('notificationclick', function(event) {
  event.notification.close();

  event.waitUntil(
    clients.openWindow('/')
  );
});

6.2 Service Worker 生命周期

下载安装激活闲置终止 默认情况下,需要关闭所有使用旧 Service Worker 的页面,新版本才会激活 可以通过 skipWaiting()clients.claim() 强制立即激活

七、Worker 中的 API 限制

7.1 可用的 API

7.2 不可用的 API

八、最佳实践和注意事项

8.1 性能优化

// 1. 使用 Transferable Objects 传输大数据
const buffer = new ArrayBuffer(1000000);
worker.postMessage({ buffer }, [buffer]);

// 2. 批量处理消息,避免频繁通信
let batch = [];
function processBatch() {
  if (batch.length > 0) {
    worker.postMessage({ batch });
    batch = [];
  }
}

// 3. 合理终止 Worker
function terminateWorkerIfIdle(worker, timeout = 60000) {
  const timer = setTimeout(() => {
    worker.terminate();
    console.log('Worker 已终止(空闲超时)');
  }, timeout);

  worker.onmessage = function() {
    clearTimeout(timer);
    // 重置计时器
    terminateWorkerIfIdle(worker, timeout);
  };
}

8.2 错误处理

// 主线程
worker.onerror = function(error) {
  console.error('Worker 错误:', error);

  // 记录错误信息
  const errorInfo = {
    filename: error.filename,
    lineno: error.lineno,
    colno: error.colno,
    message: error.message
  };

  // 重新启动 Worker(根据情况)
  if (shouldRestart(error)) {
    restartWorker();
  }
};

// Worker 内部错误处理
try {
  // 可能出错的代码
  riskyOperation();
} catch (error) {
  // 发送错误信息到主线程
  self.postMessage({
    type: 'ERROR',
    error: {
      message: error.message,
      stack: error.stack
    }
  });
}

8.3 调试技巧

// 1. 使用 console(在浏览器开发者工具的 Worker 面板查看)
console.log('Worker 日志');
console.error('Worker 错误');

// 2. 发送调试信息到主线程
self.postMessage({
  type: 'DEBUG',
  data: {
    state: 'processing',
    progress: 50,
    details: '正在处理数据...'
  }
});

// 3. 使用调试器语句
debugger; // 会在浏览器开发者工具中暂停

九、实际应用示例

9.1 图像处理 Worker

// 主线程
const imageWorker = new Worker('image-processor.js');

function processImage(imageData) {
  return new Promise((resolve, reject) => {
    imageWorker.onmessage = function(e) {
      if (e.data.type === 'SUCCESS') {
        resolve(e.data.processedData);
      } else if (e.data.type === 'ERROR') {
        reject(new Error(e.data.message));
      }
    };

    imageWorker.postMessage({
      type: 'PROCESS_IMAGE',
      imageData: imageData,
      operations: ['grayscale', 'blur', 'resize']
    });
  });
}

// 使用
canvas.toBlob(function(blob) {
  processImage(blob)
    .then(processedBlob => {
      // 更新图像显示
    })
    .catch(error => {
      console.error('图像处理失败:', error);
    });
});

9.2 实时数据处理

// data-processor.js
let dataBuffer = [];
let processing = false;

self.onmessage = function(e) {
  if (e.data.type === 'DATA_STREAM') {
    // 收集数据
    dataBuffer.push(...e.data.chunk);

    // 批量处理
    if (!processing && dataBuffer.length >= 1000) {
      processing = true;
      processBatch();
    }
  }
};

function processBatch() {
  if (dataBuffer.length === 0) {
    processing = false;
    return;
  }

  // 处理数据(不会阻塞主线程)
  const batch = dataBuffer.splice(0, 1000);
  const result = performHeavyProcessing(batch);

  // 发送结果
  self.postMessage({
    type: 'PROCESSED_DATA',
    data: result
  });

  // 继续处理下一批
  setTimeout(processBatch, 0);
}

十、兼容性和注意事项

10.1 浏览器支持

10.2 检测支持

// 检测 Worker 支持
if (typeof Worker !== 'undefined') {
  // 支持 Web Worker
}

// 检测 SharedWorker 支持
if (typeof SharedWorker !== 'undefined') {
  // 支持 SharedWorker
}

// 检测 Service Worker 支持
if ('serviceWorker' in navigator) {
  // 支持 Service Worker
}

10.3 安全限制

总结

Web Worker 为 JavaScript 提供了真正的多线程能力,是优化 Web 应用性能的重要工具。合理使用 Worker 可以将耗时任务从主线程分离,保持 UI 的流畅响应。根据不同的需求,可以选择合适的 Worker 类型:

正确使用 Worker 需要考虑通信开销、内存管理和错误处理等因素,但在适当的场景下,它能显著提升应用性能和用户体验。

相关推荐