Web Worker 与 SharedWorker 的介绍和使用
目录
- 一、Web Worker
- 1 Web Worker 是什么
- 2 Web Worker 使用
- 3 简单示例
 
- 二、SharedWorker
- 2.1 SharedWorker 是什么
- 2.2 SharedWorker 的使用方式
- 2.3 多页面数据共享的例子
 
 
 
一、Web Worker
1 Web Worker 是什么
Web Worker是 HTML5 标准的一部分,这一规范定义了一套 API。
Web Worker 允许我们在js主线程之外运行一个独立的线程(Worker),也就是运行在后台的一个独立的js脚本。因为Worker线程是独立的线程,与js主线程能够同时允许,互不阻塞。
所以如果有大量运算任务时,可以把任务交给Worker线程去处理,当Worker线程计算完成,再把结果返回给js主线程。这样,js主线程只用专注处理业务逻辑,不用耗费过多时间去处理大量复杂计算,从而减少了阻塞时间,也提高了运行效率,页面流畅度和用户体验自然而然也提高了。能解决的问题是:
1 解决页面卡死问题;
2 发挥多核CPU的优势,提高JS性能
2 Web Worker 使用
2.1 创建 worker
创建 worker 只需要通过 new 调用 Worker() 构造函数即可,它接收两个参数
const worker = new Worker(path, options);
| 参数 | 说明 | 
|---|---|
| path | 有效的js脚本的地址,必须遵守同源策略。无效的js地址或者违反同源策略,会抛出 SECURITY_ERR 类型错误 | 
| options.type | 可选,用以指定 worker 类型。该值可以是 classic或module。 如未指定,将使用默认值classic | 
| options.credentials | 可选,用以指定 worker 凭证。该值可以是 omit,same-origin,或include。如果未指定,或者 type 是classic,将使用默认值omit(不要求凭证) | 
| options.name | 可选,在 DedicatedWorkerGlobalScope的情况下,用来表示 worker 的 scope 的一个DOMString值,主要用于调试目的。 | 
2.2 主线程与 worker 线程数据传递
发送消息:postMessage()。postMessage() 方法接收的参数可以是字符串、对象、数组等接受消息:监听 message 事件
2.3 监听错误
web worker 提供两个事件监听错误,error 和 messageerror。
这两个事件的区别是:
| 事件 | 描述 | 
|---|---|
| error | 当worker内部出现错误时触发 | 
| messageerror | 当 message事件接收到无法被反序列化的参数时触发 | 
2.4 关闭 worker 线程
worker 线程的关闭在主线程和 worker 线程都能进行操作,但对 worker 线程的影响略有不同。
// main.js(主线程)
const myWorker = new Worker('/worker.js'); // 创建worker
myWorker.terminate(); // 关闭worker
// worker.js(worker线程)
self.close(); // 直接执行close方法就ok了
无论是在主线程关闭 worker,还是在 worker 线程内部关闭 worker,worker 线程当前的 Event Loop 中的任务会继续执行。至于 worker 线程下一个 Event Loop 中的任务,则会被直接忽略,不会继续执行。
区别是,在主线程手动关闭 worker,主线程与 worker 线程之间的连接都会被立刻停止,即使 worker 线程当前的 Event Loop 中仍有待执行的任务继续调用 postMessage() 方法,但主线程不会再接收到消息。
在 worker 线程内部关闭 worker,不会直接断开与主线程的连接,而是等 worker 线程当前的 Event Loop 所有任务执行完,再关闭。也就是说,在当前 Event Loop 中继续调用 postMessage() 方法,主线程还是能通过监听message事件收到消息的。
详情例子可以阅读原文:XXXX
2.5 Worker 线程引用其他js文件
总有一些场景,需要放到 worker 进程去处理的任务很复杂,需要大量的处理逻辑,我们当然不想把所有代码都塞到 worker.js 里,那样就太糟糕了。不出意料,web worker 为我们提供了解决方案,我们可以在 worker 线程中利用 importScripts() 方法加载我们需要的js文件,而且,通过此方法加载的js文件不受同源策略约束!
// utils.js
const add = (a, b) => a + b;// worker.js(worker线程)
// 使用方法:importScripts(path1, path2, ...); importScripts('./utils.js'); // 加载需要的js文件console.log(add(1, 2)); // log 3
2.6 ESModule 模式
还有一些场景,当你开启一个新项目,正高兴的用 importScripts() 导入js文件时发现, importScripts() 方法执行失败。仔细一看,原来是新项目的 js 文件都用的是 ESModule 模式。难道要把引用到的文件都改一遍吗?当然不用,还记得上文提到初始化 worker 时的第二个可选参数吗,我们可以直接使用 module 模式初始化 worker 线程!
// main.js(主线程)
const worker = new Worker('/worker.js', {type: 'module'  // 指定 worker.js 的类型
});
// utils.js
export default add = (a, b) => a + b;
// worker.js(worker线程)
import add from './utils.js'; // 导入外部jsself.addEventListener('message', e => { postMessage(e.data);
});add(1, 2); // log 3export default self; // 只需把顶级对象self暴露出去即可
2.7 主线程和 worker 线程可传递哪些类型数据
很多场景,在调用某些方法时,我们将一些自定义方法当作参数传入。但是,当你使用 postMessage() 方法时这么做,将会导致 DATA_CLONE_ERR 错误。
// main.js(主线程)
const myWorker = new Worker('/worker.js'); // 创建workerconst fun = () => {};myWorker.postMessage(fun); // Error:Failed to execute 'postMessage' on 'Worker': ()=>{} could not be cloned.
那么,使用 postMessage() 方法传递消息,可以传递哪些数据?
postMessage() 传递的数据可以是由结构化克隆算法处理的任何值或 JavaScript 对象,包括循环引用。
结构化克隆算法不能处理的数据:
- Error以及- Function对象;
- DOM 节点
- 对象的某些特定参数不会被保留 - RegExp对象的- lastIndex字段不会被保留
- 属性描述符,setters 以及 getters(以及其他类似元数据的功能)同样不会被复制。例如,如果一个对象用属性描述符标记为 read-only,它将会被复制为 read-write
- 原形链上的属性也不会被追踪以及复制。
 
结构化克隆算法支持的数据类型:
| 类型 | 说明 | 
|---|---|
| 所有的原始类型 | symbols 除外 | 
| Boolean 对象 | |
| String 对象 | |
| Date | |
| RegExp | lastIndex字段不会被保留。 | 
| Blob | |
| File | |
| FileList | |
| ArrayBuffer | |
| ArrayBufferView | 这基本上意味着所有的 类型化数组 ,如 Int32Array 等。 | 
| ImageData | |
| Array | |
| Object | 仅包括普通对象(如对象字面量) | 
| Map | |
| Set | 
3 简单示例
主线程文件 webworker.html
<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title>Web Workers</title></head><body><button onclick="startWorker()">开启 worker 线程</button><button onclick="stopWorker()">关闭 worker 线程</button><script>var myWorker;function startWorker() {// 1 创建 workermyWorker = new Worker("./workers.js");// 2 向 worker 线程发送消息myWorker.postMessage("主线程向 worker 线程发送消息");// 3 接受 worker 线程发送的消息myWorker.addEventListener("message", (e) => {console.log("主线程收到的 worker 线程发来的数据:", e.data);});// 这种写法也可以 接收消息// myWorker.onmessage = e => {//    console.log(e.data);// };// 4 监听错误myWorker.addEventListener("error", (err) => {console.log(err.message); // 当worker内部出现错误时触发});myWorker.addEventListener("messageerror", (err) => {console.log(err.message); // 当 message 事件接收到无法被反序列化的参数时触发});}// 5 在主线程中关闭 worker 线程function stopWorker() {myWorker.terminate();console.log("关闭 worker 线程");myWorker = undefined;}</script></body>
</html>
worker 线程文件 worker.js
(function () {// 接受与发送消息self.addEventListener('message', e => { // 接收到消息console.log('worker 线程收到的消息:', e.data);self.postMessage('向主线程发送消息'); // 向主线程发送消息});// 监听错误self.addEventListener('error', err => {console.log(err.message);});self.addEventListener('messageerror', err => {console.log(err.message);});// 关闭 worker 线程// self.close(); // 直接执行close方法就ok了}
)()
二、SharedWorker
2.1 SharedWorker 是什么
SharedWorker 是一种特殊类型的 Worker,可以被多个浏览上下文访问,比如多个 windows,iframes 和 workers,但这些浏览上下文必须同源。它们实现于一个不同于普通 worker 的接口,具有不同的全局作用域:SharedWorkerGlobalScope ,但是继承自WorkerGlobalScope
2.2 SharedWorker 的使用方式
SharedWorker 线程的创建和使用跟 worker 类似,事件和方法也基本一样。 不同点在于,主线程与 SharedWorker 线程是通过MessagePort建立起链接,数据通讯方法都挂载在SharedWorker.port上。
值得注意的是,如果你采用 addEventListener 来接收 message 事件,那么在主线程初始化SharedWorker() 后,还要调用 SharedWorker.port.start() 方法来手动开启端口。
// main.js(主线程)
const myWorker = new SharedWorker('./sharedWorker.js');myWorker.port.start(); // 开启端口myWorker.port.addEventListener('message', msg => {console.log(msg.data);
})但是,如果采用 onmessage 方法,则默认开启端口,不需要再手动调用SharedWorker.port.start()方法
// main.js(主线程)
const myWorker = new SharedWorker('./sharedWorker.js');myWorker.port.onmessage = msg => {console.log(msg.data);
};以上两种方式效果是一样的,具体信息请参考MessagePort。
由于 SharedWorker 是被多个页面共同使用,那么除了与各个页面之间的数据通讯是独立的,同一个SharedWorker 线程上下文中的其他资源都是共享的。基于这一点,很容易实现不同页面之间的数据通讯。
2.3 多页面数据共享的例子
一个利用SharedWorker实现多页面数据共享的例子
- index 页面的 add 按钮,每点击一次,向 sharedWorker 发送一次 add 数据,页面 count 增加1
// index.html<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8"><title>index page</title></head><body><p>index page: </p>count: <span id="container">0</span><button id="add">add</button><br>// 利用iframe加载<iframe src="./iframe.html"></iframe></body><script type="text/javascript">if (!!window.SharedWorker) {const container = document.getElementById('container');const add = document.getElementById('add');const myWorker = new SharedWorker('./sharedWorker.js');myWorker.port.start();myWorker.port.addEventListener('message', msg => {container.innerText = msg.data;});add.addEventListener('click', () => {myWorker.port.postMessage('add');});}</script>
</html>- iframe 页面的 reduce 按钮,每点击一次,向 sharedWorker 发送一次 reduce 数据,页面count 减少1
// iframe.html<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8"><title>iframe page</title></head><body><p>iframe page: </p>count: <span id="container">0</span><button id="reduce">reduce</button></body><script type="text/javascript">if (!!window.SharedWorker) {const container = document.getElementById('container');const reduce = document.getElementById('reduce');const myWorker = new SharedWorker('./sharedWorker.js');myWorker.port.start();myWorker.port.addEventListener('message', msg => {container.innerText = msg.data;})reduce.addEventListener('click', () => {myWorker.port.postMessage('reduce');});}</script>
</html>- sharedWorker 在接收到数据后,根据数据类型处理 num 计数,然后返回给每个已连接的主线程。
// sharedWorker.jslet num = 0;
const workerList = [];self.addEventListener('connect', e => {const port = e.ports[0];port.addEventListener('message', e => {num += e.data === 'add' ? 1 : -1;workerList.forEach(port => { // 遍历所有已连接的part,发送消息port.postMessage(num);})});port.start();workerList.push(port); // 存储已连接的partport.postMessage(num); // 初始化
});结果可以发现,index 页面和 iframe 页面的 count 始终保持一致,实现了多个页面数据同步。
相关文章:
Web Worker 与 SharedWorker 的介绍和使用
目录一、Web Worker1 Web Worker 是什么2 Web Worker 使用3 简单示例二、SharedWorker2.1 SharedWorker 是什么2.2 SharedWorker 的使用方式2.3 多页面数据共享的例子一、Web Worker 1 Web Worker 是什么 Web Worker是 HTML5 标准的一部分,这一规范定义了一套 API…...
React:Redux和Flux
React,用来构建用户界面,它有三个特点: 作为view,构建上用户界面虚拟DOM,目的就是高性能DOM渲染【diff算法】、组件化、多端同构单向数据流,是一种自上而下的渲染方式。Flux 在一个React应用中,UI部分是由无数个组件嵌套构成的,组件和组件之间就存在层级关系,也就是父…...
TypeScript 学习之Class
基本使用 class Greeter {// 属性greeting: string;// 构造函数constructor(message: string) {// 用this 访问类的属性this.greeting message;}// 方法greet() {return Hello, this.greeting;} } // 实例化 let greeter new Greeter(World);声明了一个Greeter类ÿ…...
 
doris - 数仓 拉链表 按天全量打宽表性能优化
数仓 拉链表 按天全量打宽性能优化现状描述优化现状描述 1、业务历史数据可以变更 2、拉链表按天打宽 3、拉链表模型分区字段设计不合理,通用的过滤字段没有作为分区分桶字段 4、拉链表表数据量略大、模型数据分区不合理和服务器资源限制,计算任务执行超…...
服务器虚拟化及优势
服务器虚拟化是从一台物理服务器创建多个服务器实例的过程。每个服务器实例代表一个隔离的虚拟环境。在每个虚拟环境中,都可以运行单独的操作系统。 1.更有效的资源调配 使用虚拟化技术大大节省了所占用的空间,减少了数据中心里服务器和相关硬件的数量。…...
 
华为ensp模拟校园网/企业网实例(同城灾备及异地备份中心保证网络安全)
文章简介:本文用华为ensp对企业网络进行了规划和模拟,也同样适用于校园、医院等场景。如有需要可联系作者,可以根据定制化需求做修改。作者简介:网络工程师,希望能认识更多的小伙伴一起交流,私信必回。一、…...
 
git命令篇(持续更新中)
首先介绍这个网页:https://learngitbranching.js.org/?localezh_CN --提交命令 git commit --创建分支 git branch <分支名> --切换分支 git checkout <分支名> --合并分支 (合并到主分支去,把我合并到谁的身上去) 自己写的分支合并到主线…...
 
用记事本实现“HelloWorld”输出
一、在任意文件夹中创建一个新的文本文档文件并写入以下代码 public class Hello{public static void main (String[] args){System.out.print("Hello,World!");} } 二、修改文件名称及文件类型为 Hello.java 特别注意:文件命名必须与代码中类的名称相同…...
 
Python基础1
1. 注释 单行注释:以#开头。一般建议注释和内容用空格隔开。 多行注释:以一对三个双引号括起来的内容是注释。“““示例注释”””。 2. 数据类型 验证数据类型的方法:type(被查看类型的数据)。 注意:…...
 
4.2 双点双向路由重发布
1. 实验目的 熟悉双点双向路由重发布的应用场景掌握双点双向路由重发布的配置方法2. 实验拓扑 双点双向路由重发布如图4-6所示: 图4-6:双点双向路由重发布 3. 实验步骤 IP地址的配置R1的配置 <Huawei>system-v…...
AcWing《蓝桥杯集训·每日一题》—— 3768 字符串删减
AcWing《蓝桥杯集训每日一题》—— 3768. 字符串删减 文章目录AcWing《蓝桥杯集训每日一题》—— 3768. 字符串删减一、题目二、解题思路三、代码实现本次博客我是通过Notion软件写的,转md文件可能不太美观,大家可以去我的博客中查看:北天的 …...
第五天笔记
1. 简述图片验证码使用流程? 1.前段生成UUID随机值,作为GET请求参数 2.后端试图进行判断,调用工具类来生成图片验证码和内容 3.将验证码内容使用redis保存到本地,前端传入的uuid作为key, 4.在前段输入获取到的图片验证码,想后端发…...
 
如何使用ArcGIS进行地理配准
1.概述 对于GIS数据而言,坐标信息是灵魂,有了坐标信息之后才能和别的数据结合使用,之前有介绍过矢量数据定义坐标信息的方法,针对栅格图,这里为大家介绍一下通过地理配准增加坐标信息的方法,希望能对你有所…...
【java基础知识】
Java中的基本数据类型是什么? byte:1字节,有符号,表示整数,范围为-128到127。short:2字节,有符号,表示整数,范围为-32768到32767。int:4字节,有符…...
 
Java提供了哪些IO方式? NIO如何实现多路复用?
第11讲 | Java提供了哪些IO方式? NIO如何实现多路复用? IO 一直是软件开发中的核心部分之一,伴随着海量数据增长和分布式系统的发展,IO 扩展能力愈发重要。幸运的是,Java 平台 IO 机制经过不断完善,虽然在某…...
人的大脑遇事的思考解决过程
人遇到问题的思考解决过程,大概如下:1) 遇到问题;2) 首先,不是直接推理,而是用直觉在自己的知识模式库里搜索,有没有相似的模式或者相同的模式。3) 如果:3a)有…...
GNU zlib 压缩与解压文件详细介绍
GNU zlib 压缩与解压文件详细介绍 1.概述 zlib 模块为 GNU 项目的 zlib 压缩库中的许多函数提供了一个低级接口 2.使用内存数据压缩与解压 2.1.压缩与解压缩 使用 zlib 的最简单方法是将所有数据保存在内存中进行压缩或解压缩。 import zlib import binasciioriginal_dat…...
 
离线环境轻量级自动化部署
流程图: 常规系统发布的痛点 服务器频繁重启,上面部署的应用服务不能随之重启,导致服务时常宕机应用手动部署相对比较麻烦,步骤繁琐应用发布环境取决于发布人本地环境,导致不同发布人每次发布环境不一致,导…...
In-context Learning
formulate the example query -> LLM -> answerno gradient descent and fine-tuning, no parameters updateadvantages: 提供了与LLM进行交流的可解释的接口,通过template和demonstration将人类知识和LLM更好的结合;更像人类的预测思维ÿ…...
【新2023】华为OD机试 - 最优调度策略(Python)
华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 最优调度策略 题目 在通信系统中有一个常见的问题是对用户进行不同策略的调度 会得到不同系统消耗的性能 假设由 N 个待串行用户,每个用户可以使用 A/B/C 三种不同的调度策略 不同的策略会消耗不同的系…...
 
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
 
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
 
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
 
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
 
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
 
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
 
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
