别再让 JavaScript 卡死页面!Web Workers 零基础上手指南

一、为什么需要多线程?

1.1 JavaScript的单线程困境

javascript 复制代码
// 主线程中的复杂计算会阻塞UI
function calculatePrimes(max) {
  const primes = [];
  for (let i = 2; i <= max; i++) {
    let isPrime = true;
    for (let j = 2; j < i; j++) {
      if (i % j === 0) {
        isPrime = false;
        break;
      }
    }
    if (isPrime) primes.push(i);
  }
  return primes;
}

// 点击按钮后界面会无法操作一段时间
document.getElementById('calculate').addEventListener('click', () => {
  const primes = calculatePrimes(100000); // 阻塞主线程
  document.getElementById('result').textContent = `找到 ${primes.length} 个质数`;
});

1.2 Web Workers的核心优势

  • 并行执行:在后台线程运行脚本
  • 非阻塞UI:保持主线程响应性
  • 隔离环境:Worker有自己的全局作用域
  • 充分利用多核CPU:现代浏览器支持多Worker并行

二、创建你的第一个Web Worker

2.1 基本结构

html 复制代码
<!-- index.html -->
<button id="start">开始计算</button>
<div id="result"></div>

<script>
  const worker = new Worker('worker.js');
  
  document.getElementById('start').addEventListener('click', () => {
    worker.postMessage({ command: 'calculate', max: 100000 });
  });
  
  worker.onmessage = (event) => {
    document.getElementById('result').textContent = 
      `找到 ${event.data.count} 个质数`;
  };
</script>
javascript 复制代码
// worker.js
self.onmessage = (event) => {
  if (event.data.command === 'calculate') {
    const primes = calculatePrimes(event.data.max);
    self.postMessage({ count: primes.length });
  }
};

function calculatePrimes(max) {
  // 同前的质数计算逻辑
}

三、高效数据传递

3.1 结构化克隆算法

javascript 复制代码
// 主线程
const complexData = {
  array: new Float32Array(1000),
  date: new Date(),
  nested: { value: '可克隆对象' }
};

worker.postMessage(complexData);

// Worker中
self.onmessage = (event) => {
  console.log(event.data.date.getFullYear()); // 正确访问
};

3.2 传输大型数据(零拷贝)

javascript 复制代码
// 传输ArrayBuffer而非复制
const buffer = new ArrayBuffer(1024 * 1024 * 100); // 100MB

// 传统方式(复制数据)
worker.postMessage({ buffer });

// 高效方式(转让所有权)
worker.postMessage({ buffer }, [buffer]);

// 主线程中buffer现在不可用
console.log(buffer.byteLength); // 0

3.3 双向通信模式

javascript 复制代码
// 主线程
worker.postMessage({ type: 'start', max: 1000000 });
worker.onmessage = (event) => {
      if (event.data.type === 'progress') {
        console.log(event.data.value);
      }
};

// Worker中
self.onmessage = (event) => {
  console.log(event.data); // 正确访问
  self.postMessage({ type: 'progress', value: 0.1 });
};

总结

如果你喜欢本教程,记得点赞+收藏!关注我获取更多JavaScript开发干货。

相关推荐
袁煦丞10 分钟前
2025.8.18实验室【代码跑酷指南】Jupyter Notebook程序员的魔法本:cpolar内网穿透实验室第622个成功挑战
前端·程序员·远程工作
Joker Zxc15 分钟前
【前端基础】flex布局中使用`justify-content`后,最后一行的布局问题
前端·css
无奈何杨18 分钟前
风控系统事件分析中心,关联关系、排行、时间分布
前端·后端
Moment23 分钟前
nginx 如何配置防止慢速攻击 🤔🤔🤔
前端·后端·nginx
晓得迷路了29 分钟前
栗子前端技术周刊第 94 期 - React Native 0.81、jQuery 4.0.0 RC1、Bun v1.2.20...
前端·javascript·react.js
江城开朗的豌豆29 分钟前
React Native 实战心得
javascript
前端小巷子30 分钟前
Vue 自定义指令
前端·vue.js·面试
玲小珑36 分钟前
Next.js 教程系列(二十七)React Server Components (RSC) 与未来趋势
前端·next.js
Mike_jia37 分钟前
UptimeRobot API状态监控:零成本打造企业级业务健康看板
前端
江城开朗的豌豆37 分钟前
React状态更新踩坑记:我是这样优雅修改参数的
前端·javascript·react.js