别再让 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开发干货。

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄3 天前
JavaScript 隐式全局变量解析
javascript
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端