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 三种不同的调度策略 不同的策略会消耗不同的系…...
Python列表系列之统计计算
Python也提供了一些内置函数去实现诸如统计、计算的功能,下面我们具体来看一下 基本语法 1、获取元素出现的次数 使用列表的count()方法可以获取元素在列表中出现的次数,语法格式如下: listname.count(obj) lisetname:列表的名…...
【蓝桥杯集训·每日一题】AcWing 1460. 我在哪?
文章目录一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解三、知识风暴二分查找哈希表一、题目 1、原题链接 1460. 我在哪? 2、题目描述 农夫约翰出门沿着马路散步,但是他现在发现自己可能迷路了! 沿路有一…...
一个不可忽视的重要能力
阅读本文大概需要 2.16 分钟。1、自我们开工后,年后第一场直播,场观二十万出头,以为是不是巧合还是卡 bug 了,就最近又测了下,发现连续几场直播下来,场观数据依旧很吓人,都是十几二十万…...
2023.2.6-2.12 AI行业周刊(第136期):住院
周末把父亲送到医院,安顿下来,这周还是决定做膝关节的手术了。 一辈子长期的劳累,加上前两年搬家时的辛苦,最终导致膝关节受损严重。 这两年来,走路每一步都很疼,纠结了很久,去了上海…...
听说2年以上的自动化测试都有16k+,4年10k的你还要等待奇迹吗?
个人简介学渣一枚,2017年6月某xx学校毕业。从事自动化测试已经4年,。2018年的时候,由于项目的原因,开始使用Robot Framework测试框架,正因为有Python的基础所以很快就理解了Robot Framework框架的工作原理,…...
git 命令实战
大家好,我是 17。 今天和大家一起用前面学过的命令做过实践。 git 命令实战 你在分支 A,一个同事在分支 B fix 了一个bug。你不方便 merge 分支B,只想更新这个 fix bug 的提交。 最先想到的是 cherry-pick,但还有两个办法,git restore&am…...
基于机器学习LSTM的古代汉语切分标注算法及语料库研究 完整代码+数据+论文
完整代码:https://download.csdn.net/download/qq_38735017/87382302摘 要近年来,深度学习的浪潮渗透在科研和生活领域的方方面面,本文主要研究深度学习在自然语言处理,尤其是古汉语自然语言处理方面的应用。本文旨在利用计算机帮…...
魔百和M401A刷入Armbian系统EMMC开启wifi
文章目录一、Armbian系统写入U盘二、U盘内uEnv.txt文件修改三、盒子从U盘进行启动四、设置用户名和密码五、Armbian系统写入EMMC六、 重启系统reboot(不可以拔U盘)七、盒子关机拔出U盘八、插入USB无线网卡,连接wifi上次盒子刷了5.15版本的armbian系统,可…...
超实用的小红书内容营销策略分享!纯干货
抓住小红书内容流量密码就是掌握了财富,越来越多的品牌方和商家都在小红书上收获了相当可观的用户流量,如果你的小红书营销没有什么起色,那绝对是没有走对方向。 小红书是一个内容为王的平台,如果你还不懂下面这些小红书内容营销…...
高压放大器在介电泳效应的细胞分选研究中的应用
实验名称:高压放大器在介电泳效应的细胞分选研究中的应用研究方向:生物医学测试目的:细胞分选在分析化学和生物医药领域有着非常重要的应用。在众多的分选方法中,微流控分选方法以其响应速度快、样品需求少等优点成为研究热门。微…...
wordpress 自动跳转/网站seo外包
点击查看全文 讲师介绍 刘立兼 上海云贝网络科技有限公司首席架构师,数年来一直奋战在电商大数据领域。经历了一个又一个618/1111/1212。对面向大数据的高可用、高性能、易扩展的分布式架构技术有着深刻的理解,特别擅长基于云计算的系统架构。 直播…...
犀牛做网站的公司/西青seo
括号检查 题目 现有一字符串 仅由 (,),{,},[,] 六种括号组成,若字符串满足以下条件之一,则为无效字符串 任意类型的左右括号数量不相等 存在未按正确顺序(先左后右)闭合的括号, 输出括号的最大嵌套深度 若字符串无效则输出 0 0 <= 字符串长度 <= 100000 输入 一个只…...
网站编程工具/百度 营销推广怎么收费
前言 在去年十月的时候参加了一个小比赛,做了一个人脸识别程序并很意外地获得省里面的一等奖,视频演示链接在这里,有同学想要做这方面的毕业设计or课程设计,发一篇博客来分享一下当时的开发过程。 视频演示链接 Github链接 项目简…...
一级a做爰片免费网站丶/广告营销顾问
夜光序言: 既然选择了远方,便只顾风雨兼程,哪管山高路远。 正文:...
用asp做网站遇到的问题/线上销售渠道有哪些
查看配置文件:https://raw.githubusercontent.com/antirez/redis/5.0.3/redis.conf 主要参数说明 redis.conf 配置项说明如下: 序号配置项说明1 daemonize no Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 y…...
做旅游网站平台ppt/最佳的搜索引擎
描述适合3ePIC试验板,爱晶产品销售服务做的不好,好多C程序都是自己写的,不过汇编程序参考一下不错。;------------------------------------------------------------------------------------------;单双位变换显示实验参考程序注意…...