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

相关推荐
三小河6 分钟前
前端视角详解 Agent Skill
前端·javascript·后端
Aniugel19 分钟前
单点登录(SSO)系统
前端
颜酱19 分钟前
二叉树遍历思维实战
javascript·后端·算法
鹏多多22 分钟前
移动端H5项目,还需要react-fastclick解决300ms点击延迟吗?
前端·javascript·react.js
serioyaoyao24 分钟前
上万级文件一起可视化,怎么办?答案是基于 ParaView 的远程可视化
前端
万少30 分钟前
端云一体 一天开发的元服务-奇趣故事匣经验分享
前端·ai编程·harmonyos
WindrunnerMax32 分钟前
从零实现富文本编辑器#11-Immutable状态维护与增量渲染
前端·架构·前端框架
不想秃头的程序员34 分钟前
Vue3 封装 Axios 实战:从基础到生产级,新手也能秒上手
前端·javascript·面试
数研小生1 小时前
亚马逊商品列表API详解
前端·数据库·python·pandas
你听得到111 小时前
我彻底搞懂了 SSE,原来流式响应效果还能这么玩的?(附 JS/Dart 双端实战)
前端·面试·github