全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-16 10 分钟 ✍️ juanwangdev

Web Worker 多线程优化

Web Worker让JavaScript支持多线程执行,将耗时任务移出主线程,避免阻塞UI渲染。

核心概念

主线程限制

JavaScript
// ❌ 主线程执行耗时任务
function heavyCalculation() {
  let result = 0;
  for (let i = 0; i < 1000000000; i++) {
    result += Math.sqrt(i);
  }
  return result;
}

// 执行时页面卡死,无法响应用户交互
const result = heavyCalculation();

Worker架构

JavaScript
主线程(UI线程)
    ↓ 创建
Worker线程(计算线程) → 并行执行
    ↑ 通信
消息传递(postMessage/onmessage)

Worker特点

  • 独立线程:不阻塞主线程
  • 受限环境:无法访问DOM、window对象
  • 消息通信:通过postMessage传递数据
  • 脚本隔离:独立作用域,无共享状态

基础用法

创建Worker

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

// 发送消息
worker.postMessage({ type: 'calculate', data: { n: 1000000 } });

// 接收消息
worker.onmessage = (event) => {
  console.log('Worker result:', event.data);
};

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

// 终止Worker
worker.terminate();

Worker脚本

JavaScript
// worker.js
self.onmessage = (event) => {
  const { type, data } = event.data;

  if (type === 'calculate') {
    const result = heavyCalculation(data.n);
    self.postMessage({ type: 'result', result });
  }
};

function heavyCalculation(n) {
  let result = 0;
  for (let i = 0; i < n; i++) {
    result += Math.sqrt(i);
  }
  return result;
}

// Worker内部可以使用
// - setTimeout/setInterval
// - fetch/XMLHttpRequest
// - WebSocket
// - IndexedDB
// - console.log

内联Worker

JavaScript
// 使用Blob创建内联Worker
const workerCode = `
  self.onmessage = (e) => {
    const result = e.data.map(x => x * x);
    self.postMessage(result);
  };
`;

const blob = new Blob([workerCode], { type: 'application/javascript' });
const workerUrl = URL.createObjectURL(blob);
const worker = new Worker(workerUrl);

worker.postMessage([1, 2, 3, 4, 5]);
worker.onmessage = (e) => console.log(e.data);

// 清理URL
URL.revokeObjectURL(workerUrl);

Worker通信机制

基本通信

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

// 发送
worker.postMessage({
  action: 'process',
  payload: { data: [1, 2, 3] }
});

// 接收
worker.addEventListener('message', (event) => {
  const response = event.data;
  console.log('Response:', response);
});

// Worker线程
self.addEventListener('message', (event) => {
  const { action, payload } = event.data;

  if (action === 'process') {
    const result = processData(payload.data);
    self.postMessage({ action: 'result', result });
  }
});

Transferable对象

JavaScript
// 大数据传输优化
const buffer = new ArrayBuffer(1024 * 1024); // 1MB

// ❌ 默认拷贝传输
worker.postMessage(buffer); // 拷贝数据,耗时

// ✅ 转移所有权,零拷贝
worker.postMessage(buffer, [buffer]); // 转移后主线程无法访问buffer

// 示例:图像处理
const imageData = canvas.getImageData(0, 0, width, height);
worker.postMessage(imageData, [imageData.data.buffer]);

SharedArrayBuffer

JavaScript
// 共享内存(需特殊安全配置)
const sharedBuffer = new SharedArrayBuffer(1024);
const sharedArray = new Int32Array(sharedBuffer);

// 主线程和Worker共享同一内存
worker.postMessage({ buffer: sharedBuffer });

// Worker写入
sharedArray[0] = 100;

// 主线程读取
console.log(sharedArray[0]); // 100

// 同步操作使用Atomics
Atomics.store(sharedArray, 0, 200);
Atomics.load(sharedArray, 0); // 200

Worker类型

Dedicated Worker

JavaScript
// 专用Worker:只能被创建者使用
const worker = new Worker('dedicated.js');
worker.postMessage('hello');

Shared Worker

JavaScript
// 共享Worker:多个页面共享同一Worker
const worker = new SharedWorker('shared.js');

// 通过port通信
worker.port.onmessage = (event) => {
  console.log('Shared worker message:', event.data);
};
worker.port.postMessage('hello from page A');

// shared.js
self.onconnect = (event) => {
  const port = event.ports[0];
  port.onmessage = (e) => {
    port.postMessage('response');
  };
};

Service Worker

JavaScript
// Service Worker:用于缓存和离线
// 注册
navigator.serviceWorker.register('/sw.js');

// sw.js
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v1').then(cache => cache.addAll(['/']))
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

实际应用场景

数据处理

JavaScript
// 主线程
const worker = new Worker('data-processor.js');

async function processLargeData(data) {
  return new Promise((resolve) => {
    worker.onmessage = (event) => {
      resolve(event.data);
    };
    worker.postMessage(data);
  });
}

// data-processor.js
self.onmessage = (event) => {
  const data = event.data;
  const processed = data.map(transform).filter(validate);
  self.postMessage(processed);
};

function transform(item) {
  // 复杂转换逻辑
  return { ...item, processed: true };
}

图像处理

JavaScript
// 图像滤镜处理
const worker = new Worker('image-worker.js');

function applyFilter(imageData, filter) {
  return new Promise((resolve) => {
    worker.onmessage = (event) => {
      resolve(event.data);
    };
    worker.postMessage({ imageData, filter }, [imageData.data.buffer]);
  });
}

// image-worker.js
self.onmessage = (event) => {
  const { imageData, filter } = event.data;
  const processed = applyFilterToImageData(imageData, filter);
  self.postMessage(processed, [processed.data.buffer]);
};

function applyFilterToImageData(imageData, filter) {
  const data = imageData.data;
  for (let i = 0; i < data.length; i += 4) {
    // 灰度滤镜
    if (filter === 'grayscale') {
      const avg = (data[i] + data[i+1] + data[i+2]) / 3;
      data[i] = data[i+1] = data[i+2] = avg;
    }
  }
  return imageData;
}

加密解密

JavaScript
// 加密Worker
const cryptoWorker = new Worker('crypto-worker.js');

async function encryptData(data, key) {
  return new Promise((resolve) => {
    cryptoWorker.onmessage = (event) => {
      resolve(event.data);
    };
    cryptoWorker.postMessage({ action: 'encrypt', data, key });
  });
}

// crypto-worker.js
self.onmessage = async (event) => {
  const { action, data, key } = event.data;

  if (action === 'encrypt') {
    const encrypted = await encrypt(data, key);
    self.postMessage({ action: 'encrypted', result: encrypted });
  }
};

async function encrypt(data, key) {
  const algorithm = { name: 'AES-GCM', iv: crypto.getRandomValues(new Uint8Array(12)) };
  const cryptoKey = await crypto.subtle.importKey('raw', key, algorithm, false, ['encrypt']);
  const encrypted = await crypto.subtle.encrypt(algorithm, cryptoKey, data);
  return encrypted;
}

大文件解析

JavaScript
// CSV/JSON大文件解析
const parserWorker = new Worker('parser-worker.js');

function parseLargeFile(file) {
  return new Promise((resolve) => {
    parserWorker.onmessage = (event) => {
      resolve(event.data);
    };

    const reader = new FileReader();
    reader.onload = (event) => {
      parserWorker.postMessage({ content: event.target.result, type: file.type });
    };
    reader.readAsText(file);
  });
}

// parser-worker.js
self.onmessage = (event) => {
  const { content, type } = event.data;

  if (type === 'text/csv') {
    const rows = parseCSV(content);
    self.postMessage(rows);
  } else if (type === 'application/json') {
    const data = JSON.parse(content);
    self.postMessage(data);
  }
};

function parseCSV(content) {
  const lines = content.split('\n');
  return lines.map(line => line.split(','));
}

Worker池管理

Worker池实现

JavaScript
class WorkerPool {
  constructor(workerScript, poolSize = 4) {
    this.workers = [];
    this.taskQueue = [];
    this.activeTasks = new Map();

    for (let i = 0; i < poolSize; i++) {
      const worker = new Worker(workerScript);
      worker.id = i;
      worker.onmessage = this.handleMessage.bind(this);
      worker.onerror = this.handleError.bind(this);
      this.workers.push({ worker, busy: false });
    }
  }

  runTask(data) {
    return new Promise((resolve, reject) => {
      const availableWorker = this.workers.find(w => !w.busy);

      if (availableWorker) {
        this.executeTask(availableWorker, data, resolve, reject);
      } else {
        this.taskQueue.push({ data, resolve, reject });
      }
    });
  }

  executeTask(workerInfo, data, resolve, reject) {
    workerInfo.busy = true;
    const taskId = Date.now();

    this.activeTasks.set(taskId, {
      workerInfo,
      resolve,
      reject
    });

    workerInfo.worker.postMessage({ taskId, data });
  }

  handleMessage(event) {
    const { taskId, result } = event.data;
    const task = this.activeTasks.get(taskId);

    if (task) {
      task.workerInfo.busy = false;
      task.resolve(result);
      this.activeTasks.delete(taskId);

      // 处理队列中的下一个任务
      if (this.taskQueue.length > 0) {
        const nextTask = this.taskQueue.shift();
        this.executeTask(task.workerInfo, nextTask.data, nextTask.resolve, nextTask.reject);
      }
    }
  }

  handleError(error) {
    console.error('Worker error:', error);
  }

  terminate() {
    this.workers.forEach(w => w.worker.terminate());
  }
}

// 使用
const pool = new WorkerPool('worker.js', 4);

const results = await Promise.all([
  pool.runTask({ action: 'calc', data: 1 }),
  pool.runTask({ action: 'calc', data: 2 }),
  pool.runTask({ action: 'calc', data: 3 }),
]);

最佳实践

任务分片

JavaScript
// 大任务分片处理
function chunkedProcessing(worker, data, chunkSize = 1000) {
  const chunks = [];
  for (let i = 0; i < data.length; i += chunkSize) {
    chunks.push(data.slice(i, i + chunkSize));
  }

  return Promise.all(
    chunks.map(chunk => {
      return new Promise(resolve => {
        worker.onmessage = (event) => resolve(event.data);
        worker.postMessage(chunk);
      });
    })
  );
}

错误处理

JavaScript
// Worker错误捕获
worker.onerror = (error) => {
  console.error('Worker error:', {
    message: error.message,
    filename: error.filename,
    lineno: error.lineno
  });

  // 重启Worker
  worker.terminate();
  worker = new Worker('worker.js');
};

终止管理

text
// 页面卸载时终止Worker
window.addEventListener('beforeunload', () => {
  worker.terminate();
});

// React组件清理
useEffect(() => {
  const worker = new Worker('worker.js');

  return () => {
    worker.terminate();
  };
}, []);

要点总结

  1. 独立线程:Worker不阻塞主线程,适合耗时任务
  2. 受限环境:无法访问DOM,只能通过消息通信
  3. Transferable:大数据使用转移所有权,零拷贝
  4. Worker池:管理多个Worker,队列分发任务
  5. 典型场景:数据处理、图像处理、加密、文件解析
  6. 生命周期:创建→通信→终止,及时清理

存放路径:articles/JS/专家/高级性能分析/Web Worker 多线程优化.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 DOM 操作优化与重排重绘
下一篇 → 代码分割与懒加载
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库