当前位置: 首页 > news >正文

Web Worker 入门指南

在浏览器环境中,JavaScript 是单线程运行的,这意味着当执行一些耗时的操作时(例如大量计算、数据处理等),会阻塞主线程,导致用户界面卡顿,影响用户体验。为了解决这个问题,Web Worker 提供了一种在后台线程中运行脚本的方法,从而避免阻塞主线程。

1. 什么是 Web Worker

Worker 是一个使用构造函数创建的对象(例如 Worker()),它运行一个具名 JavaScript 文件,该文件包含将在 Worker 线程中运行的代码。Worker 运行在另一个全局上下文中,不同于当前的 window。在 Worker 内通过 self 获取全局作用域,而不是 window。

2. Web Worker 的基本用法

2.1 创建 Worker 线程

要创建一个 Worker,需要使用 Worker 构造函数,并传入一个 JavaScript 文件的路径作为参数。例如,假设我们有一个名为 worker.js 的文件:

// worker.js
self.onmessage = (event) => {console.log('worker event: ', event)
};
// 主线程
const worker = new Worker('worker.js');

注:这里的 worker.js 必须与主线程在同一域名下。如果使用构建工具,还需要注意打包后的路径问题

2.2 主线程发送消息给 Worker 线程

要向 Worker 线程发送消息,需要调用 worker.postMessage() 方法,并传入一个要发送的数据作为参数。例如:

// 主线程
const worker = new Worker('worker.js');
worker.postMessage({ num: 10 });

运行后我们可以看到 Worker 线程中接收到的 event.data 属性就是在主线程中传入的值
img

2.3 接收 Worker 线程的消息

在 Worker 线程中,我们可以使用 self.postMessage() 方法向主线程发送消息。主线程可以通过监听 worker.onmessage 事件来接收这些消息。例如:

// worker.js
self.onmessage = (event) => {console.log('worker event: ', event)const { num } = event.data;const result = num + 1;self.postMessage({ value: result });
};
// 主线程
const worker = new Worker('worker.js');
worker.postMessage({ num: 10 });worker.onmessage = (event) => {console.log('main event: ', event);
};

运行后我们可以看到主线程中接收到了 Worker 线程发送的消息,其中 event.data 属性就是 Worker 线程中计算后的结果
img

这样我们就可以把主线程中的耗时操作放到 Worker 线程中执行,等待 Worker 线程执行完成后将结果返回给主线程,从而避免阻塞主线程,提升用户体验

2.4 关闭 Worker 线程

当 Worker 线程不再需要时,应该调用 worker.terminate() 方法来关闭它。这将释放 Worker 线程占用的资源。例如:

// 主线程
const worker = new Worker('worker.js');
worker.postMessage({ num: 10 });worker.onmessage = (event) => {console.log('main event: ', event);worker.terminate();
};

通过 Source 面板对比我们可以看到,调用 worker.terminate() 后 Worker 线程被销毁
img

3. 嵌入式 Worker 线程

有时候我们可能不想单独创建一个 JavaScript 文件来作为 Worker 线程的脚本,这时可以使用 Blob 对象来创建一个内联的 Worker 线程。例如:

const workerScript = `self.onmessage = (event) => {console.log('worker event: ', event)const { num } = event.data;const result = num + 1;self.postMessage({ value: result });};
`;const workerBlob = new Blob([workerScript], { type: 'text/javascript' });
const workerUrl = URL.createObjectURL(workerBlob);
const worker = new Worker(workerUrl);worker.postMessage({ num: 10 });worker.onmessage = (event) => {console.log('main event: ', event);
};

运行后同样可以看到 Worker 线程接收到了主线程的消息,主线程也接收到了 Worker 线程处理后的结果
img

4. 调试 Worker 线程

在浏览器的开发者工具中,可以通过 Source 面板查看和调试 Worker 线程。Worker 线程会显示在 Sources 面板的 Workers 部分,可以像调试主线程一样设置断点、查看变量等

  • 如果使用单独的 JavaScript 文件作为 Worker 线程的脚本,我们可以在 Source 面板通过文件名找到对应的 Worker 文件
    img

  • 如果使用内联的 Worker 线程脚本,Source 面板会有一个随机字符串作为 Worker 文件名,且每次重新加载文件名都会发生变化
    img

5. React 中使用 Worker 线程

import { useCreation } from 'ahooks';
import { Button } from 'antd';
import { useState } from 'react';const workerScript = `self.onmessage = (event) => {const { num } = event.data;const result = num + 1;self.postMessage({ value: result });};
`;export default function WebWorkerPage() {const [num, setNum] = useState(0);const worker = useCreation(() => {const workerBlob = new Blob([workerScript], { type: 'text/javascript' });const workerUrl = URL.createObjectURL(workerBlob);const worker = new Worker(workerUrl);worker.onmessage = (event) => {console.log('main event: ', event.data);setNum(event.data.value);};return worker;}, []);return (<div className="WebWorkerPage"><h4>{num}</h4><Button onClick={() => worker.postMessage({ num })}>Add</Button></div>);
}

示例中使用嵌入式 Worker 线程的方式,并通过 useCreation hook 来创建 Worker 线程,确保只创建一次 Worker 线程实例
点击 Add 按钮后,会向 Worker 线程发送主线程的 num 值,Worker 线程计算 num + 1(可替换为其他阻塞主线程的耗时操作),并将结果返回给主线程,主线程更新 num 的值并显示在页面上
img

参考文档:使用 Web Worker

http://www.jsqmd.com/news/37750/

相关文章:

  • 鸿蒙NEXT系列之精析NDK UI API(节点增删和属性设置) - 实践
  • 通用cursor rules总结
  • 【JVS更新日志】开源框架升级vue 3、低代码、企业计划、智能BI及其他产品迎来新版本! - 实践
  • 银川西林瓶灌装旋盖机推荐2025,运行稳定连续8小时无故障
  • 【ACM出版 | EI检索稳定】2025年人工智能、业务转型和数据科学创新国际学术会议(ICBTDS 2025)
  • echarts 树形结构图实例
  • pg_hba.conf配置里peer,indent和md5的区别
  • 基于Simulink的双电机PID控制仿真实现方案
  • 锡林郭勒西林瓶灌装清洗耗材月成本分析?查行情享优惠
  • AI Agent OS 探索有价值的论文分析(1):Sleep-time Compute
  • Linux内核架构浅谈26-Linux实时进程调度:优先级反转与解决实用的方案
  • 宏定义的高级应用
  • 被问性能后,我封装了这个 PHP 错误上报工具
  • 公众号中的贴纸素材有什么作用?在哪里找?
  • 国标GB28181算法算力平台EasyGBS:深度解析全场景视频调阅功能与行业实战应用
  • 2025出国留学机构综合实力榜:排名前十的留学中介特色分析
  • 公众号怎么起爆款标题?有什么好用的工具?
  • 邢台西林瓶灌装机优选指南:聚焦资质、案例与售后
  • 基于SpringBoot+Vue的个人理财系统管理系统设计与建立【Java+MySQL+MyBatis完整源码】
  • python使用PyInstaller打包成exe
  • 2025年机械磨优质厂家权威推荐榜单:冲击磨/小型机械磨/超微机械磨源头厂家精选
  • jQuery custom content scroller滚动条控件代码 - 教程
  • 【APIE出版 | EI检索快速稳定】2025年机电一体化与轨道、交通国际学术会议(MRT 2025)
  • 搭建第一个MCP服务
  • React-router v7 配置 Suspense+lazy fallback第二次不显示
  • spark read mongodb拉取的数据行数和源库不一致
  • PV 与 PVC 的“绑定”动作真正发生的时间点
  • 2025日本留学中介推荐:留学申请与语言学习一站式解决
  • 2025年11月高温老化房及环境试验设备推荐厂家:步入式恒温试验室/步入式高低温湿热试验室/大型高低温湿热试验室/汽车零部件、逆变器、电子元器件等场景适用
  • 【ACM出版 | 最快会后4个月检索 | 往届均已成功见刊并被EI检索】第三届人工智能、系统与网络安全国际学术会议 (AISNS 2025)