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

相关推荐
码上成长2 小时前
GraphQL:让前端自己决定要什么数据
前端·后端·graphql
冴羽2 小时前
为什么在 JavaScript 中 NaN !== NaN?背后藏着 40 年的技术故事
前端·javascript·node.js
久爱@勿忘2 小时前
vue下载项目内静态文件
前端·javascript·vue.js
前端炒粉2 小时前
21.搜索二维矩阵 II
前端·javascript·算法·矩阵
合作小小程序员小小店3 小时前
web网页开发,在线%台球俱乐部管理%系统,基于Idea,html,css,jQuery,jsp,java,ssm,mysql。
java·前端·jdk·intellij-idea·jquery·web
不爱吃糖的程序媛3 小时前
Electron 应用中的系统检测方案对比
前端·javascript·electron
泷羽Sec-静安3 小时前
Less-9 GET-Blind-Time based-Single Quotes
服务器·前端·数据库·sql·web安全·less
pe7er3 小时前
用高阶函数实现递归:从匿名函数到通用递归生成器
前端·javascript
IT古董4 小时前
全面理解 Corepack:Node.js 的包管理新时代
前端·node.js·corepack
Jonathan Star4 小时前
NestJS 是基于 Node.js 的渐进式后端框架,核心特点包括 **依赖注入、模块化架构、装饰器驱动、TypeScript 优先、与主流工具集成** 等
开发语言·javascript·node.js