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

一文了解Web Worker

一、概述

众所周知,JavaScript最初设计是运行在浏览器中的,为了防止多个线程同时操作DOM带来的渲染冲突问题,所以JavaScript执行器被设计成单线程。但是随着前端技术的发展,JavaScript要处理的工作也越来越复杂,当我们遇到需要大量计算的场景时,比如图像处理、视频解码、耗时计算等场景时,JavaScript的主线程就会被长时间阻塞,甚至造成页面卡顿,影响用户体验。

为了实现异步编程,JavaScript先后出现了AJAX、Promises、async/await 等技术,当然,本文要讲的Web Worker技术也可以实现异步编程。目前,主流的浏览器都支持Web Worker。

image.png

二、Web Worker简介

Web Worker是 HTML5 标准的一部分,这一规范定义了一套 API,允许开发者在 JavaScript 主线程之外开辟新的 Worker 线程,并允许将一段 JavaScript 脚本运行其中。Web Worker的出现,赋予了开发者操作多线程的能力。

因为是独立的线程,Worker 线程与JavaScript主线程是能够同时运行的,且互不阻塞。所以,在应对需要异步操作的场景时,我们可以把运算任务交给 Worker 线程去处理,当 Worker 线程计算完成,再把结果返回给 JavaScript 主线程。这样,JavaScript 主线程只用专注处理业务逻辑,不用耗费过多时间去处理大量复杂计算,从而实现异步编程效果,提升开发和运行效率。

事实上,虽然 Worker 线程是在浏览器环境中被唤起,但是它与当前页面窗口运行在不同的全局上下文中,我们常用的顶层对象 window,以及 parent 对象在 Worker 线程上下文中是不可用的。另外,在 Worker 线程上下文中,操作 DOM 的行为也是不可行的,document对象也不存在。但是,location和navigator对象可以以可读方式访问。除此之外,绝大多数 Window 对象上的方法和属性,都被共享到 Worker 上下文全局对象 WorkerGlobalScope 中。同样,Worker 线程上下文也存在一个顶级对象 self。

三、基本使用

3.1 检查是否支持Web Worker

在创建 web worker 之前,请检查用户的浏览器是否支持它,示例代码如下。

if (typeof(Worker) !== "undefined") {// Yes! Web worker support!
} else {// Sorry! No Web Worker support..
}

3.2 创建Work

创建worker只需要通过new方式调用 Worker() 构造函数即可,它接收两个参数:

const worker = new Worker(path, options);

当然,不传options也是可以的。其中,path和options含义如下:

  • path:有效的js脚本的地址,必须遵守同源策略。
  • options.type:可选,用以指定 worker 类型,可选值为classic、module。
  • options.credentials:可选,指定 worker 凭证,可选值omit、same-origin和nclude
  • options.name:可选,在 DedicatedWorkerGlobalScope 的情况下,用来表示 worker 的 scope 的一个 DOMString 值,主要用于调试目的。

3.3 数据传递

主线程与Worker线程都可以通过 postMessage 方法来发送消息,然后使用监听 message 事件来接收消息。

main.js

const myWorker = new Worker('/worker.js');  
//接受消息
myWorker.addEventListener('message', e => {  console.log(e.data);  
});//发送消息
myWorker.postMessage('Greeting from Main.js'); 

而使用postMessage() 方法传递的数据类型可以是字符串、对象、数组等。

3.4 监听错误信息

对于监听message事件的错误信息,Web Worker提供两个事件来监听错误,分别error 和 messageerror。这两个事件的区别是:

  • error:当worker内部出现错误时触发。
  • messageerror:当 message 事件接收到无法被反序列化的参数时触发。

当然,监听错误信息的调用方式是一样的。

const myWorker = new Worker('/worker.js');  myWorker.addEventListener('error', err => {console.log(err.message);
});myWorker.addEventListener('messageerror', err => {console.log(err.message)
});

3.5 关闭Web Worker

当Web Worker对象被创建时,它就开启了消息监听直到它被终止。所以,为了避免造成资源浪费,需要在使用结束之后放浏览器/计算机资源。不过,在主线程和在Worker线程的关闭方式是不一样的。如果在主线程,调用terminate()方法关闭即可:

const myWorker = new Worker('/worker.js');  
myWorker.terminate();  

如果是在Work线程则可以调用close()方法进行关闭:

self.close(); 

需要说明的是,无论是在主线程关闭 Worker,还是在 Worker 线程内部关闭 Worker,Worker 线程当前的 Event Loop 中的任务会继续执行。至于 Worker 线程下一个 Event Loop 中的任务,则会被直接忽略,不会继续执行。

区别是,在主线程手动关闭 Worker,主线程与 Worker 线程之间的连接都会被立刻停止,此时如果继续调用postMessage() 方法发送消息,但主线程不会再接收到消息。而在 Worker 线程内部关闭 Worker,不会直接断开与主线程的连接,而是等 Worker 线程当前的 Event Loop 所有任务执行完,再关闭。也就是说,此时Worker线程可以继续调用 postMessage()方法。

3.6 Worker 线程引入JavaScript文件

有时候,我们需要在Worker 线程中处理一些复杂的业务逻辑,为了保证代码整体结构的美观,我们希望把代码单独开来,而不是都塞到Worker.js 里。为此,我们可以使用Web Work提供的importScripts() 方式来引入另一个JavaScript文件,而通过此方法加载JavaScript文件是不受同源策略约束的。

add.js

const add = (a, b) => a + b;

然后,在Worker线程中使用importScripts引入add.js。

importScripts('./add.js');console.log(add(1, 2));  

3.7 ESModule

有时候,当我们使用importScripts()方式导入JavaScript文件时出现执行失败,分析后发现原来项目的 JavaScript 文件都用的是 ESModule 模式。那么对于这种场景,我们需要怎么引入呢?

对于这种场景,我们需要在初始化Worker时传入可选参数option,我们可以直接使用 module 模式初始化 worker 线程。

const worker = new Worker('/worker.js', {type: 'module'   
});

四、SharedWorker

SharedWorker 是一种特殊类型的 Worker,可以被多个浏览上下文访问,比如多个 windows,iframes 和 workers,但使用的前提是这些浏览上下文必须同源。

SharedWorker 线程的创建和使用跟 Worker 类似,事件和方法也基本一样。不同点在于,主线程与 SharedWorker 线程是通过MessagePort建立起链接,数据通讯方法都挂载在SharedWorker.port上。

并且需要说明的是,如果采用 addEventListener 来接收 message 事件,那么在主线程初始化SharedWorker() 后,还要调用 SharedWorker.port.start() 方法来手动开启端口。

SharedWorker的基本使用:

const myWorker = new SharedWorker('./sharedWorker.js');myWorker.port.start(); // 开启端口myWorker.port.addEventListener('message', msg => {console.log(msg.data);
})

如果采用 onmessage()方法接收事件,则默认开启端口,不需要再手动调用SharedWorker.port.start()方法。

const myWorker = new SharedWorker('./sharedWorker.js');myWorker.port.onmessage = msg => {console.log(msg.data);
};

对于SharedWorker的调试,我们可以在 sharedWorker 线程里使用 console 打印信息,不会出现在主线程的的控制台中。如果你想调试 sharedWorker,需要在 Chrome 浏览器输入 chrome://inspect/ ,这里能看到所有正在运行的 sharedWorker,然后开启一个独立的 dev-tool 面板。

image.png

相关文章:

一文了解Web Worker

一、概述 众所周知,JavaScript最初设计是运行在浏览器中的,为了防止多个线程同时操作DOM带来的渲染冲突问题,所以JavaScript执行器被设计成单线程。但是随着前端技术的发展,JavaScript要处理的工作也越来越复杂,当我们…...

接口文档包含哪些内容?怎么才能写好接口文档?十年测试老司机来告诉你

目录 接口文档结构 参数说明 示例 错误码说明 语言基调通俗易懂 及时更新与维护 总结 那么我们该如何写好一份优秀的接口文档呢? 接口文档结构 首先我们要知道文档结构是什么样子的。接口文档应该有清晰明确的结构,以便开发人员能快速定位自己需…...

java面试八股文之------Java并发夺命23问

java面试八股文之------Java并发夺命23问👨‍🎓1.java中线程的真正实现方式👨‍🎓2.java中线程的真正状态👨‍🎓3.如何正确停止线程👨‍🎓4.java中sleep和wait的区别👨‍…...

CANoe中使用CAPL刷写流程详解(Trace图解)(CAN总线)

🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】🍅 玩转CANoe&…...

【MySQL】002 -- 日志系统:一条SQL更新语句是如何执行的

此文章为《MySQL 实战 45 讲》的学习笔记,其课程链接可参见:MySQL实战45讲_MySQL_数据库-极客时间 目录 一、日志系统 1、重做日志:redo log(引擎层) 2、归档日记:binlog(Server层) …...

C++---背包模型---数字组合(每日一道算法2023.3.14)

注意事项: 本题是"动态规划—01背包"的扩展题,优化思路不多赘述,dp思路会稍有不同,下面详细讲解。 题目: 给定 N个正整数 A1,A2,…,AN,从中选出若干个数,使它们的和为 M,…...

并查集(不相交集)详解

目录 一.并查集 1.什么是并查集 2.并查集的基本操作 3.并查集的应用 4.力扣上的题目 二.三大操作 1.初始化 2.查找 3.合并 三.省份数量 1.题目描述 2.问题分析 3.代码实现 四.冗余连接 1.题目描述 2.问题分析 3.代码实现 一.并查集 1.什么是并查集 并查集&…...

10个最频繁用于解释机器学习模型的 Python 库

文章目录什么是XAI?可解释性实践的步骤技术交流1、SHAP2、LIME3、Eli54、Shapash5、Anchors6、BreakDown7、Interpret-Text8、aix360 (AI Explainability 360)9、OmniXAI10、XAI (eXplainable AI)XAI的目标是为模型的行为和决定提供有意义的解释,本文整理…...

final关键字:我偏不让你继承

哈喽,小伙伴们大家好,我是兔哥呀,今天就让我们继续这个JavaSE成神之路! 这一节啊,咱们要学习的内容是Java所有final关键字。 之前呢,我们学习了继承,这大大提高了代码的灵活性和复用性。但是总…...

8大主流编程语言的适用领域,你可能选错了语言

很多人学编程经常是脑子一热然后就去网上一搜资源就开始学习了,但学到了后面发现目前所学的东西并不是自己最喜欢的,好像自己更喜欢另一个技术,感觉自己学错了,于是乎又去学习别的东西。 结果竹篮打水一场空,前面所付…...

关于Python库的问题

关于Python库的问题 问题1: ModuleNotFoundError: No module named ‘requests’ Python库 Pycharm使用Requests库时报错: No module named requests’解决方法 未安装requests库,使用"pip install requests"命令安装 依然提示P…...

好记性不如烂笔头(2)

概述:用来记录一些小技巧。 1.查看MyBatis执行的sql 类:org.apache.ibatis.mapping.MappedStatement方法:getBoundSql(Object parameterObject)在IDEA的Evaluate Expression查看sql:boundSql.getSql() 2.maven仓库地址为https&…...

Java for循环嵌套for循环,你需要懂的代码性能优化技巧

前言 本篇分析的技巧点其实是比较常见的,但是最近的几次的代码评审还是发现有不少兄弟没注意到。 所以还是想拿出来说下。 正文 是个什么场景呢? 就是 for循环 里面还有 for循环, 然后做一些数据匹配、处理 这种场景。 我们结合实例代码来…...

关于我拒绝了腾讯测试开发岗offer这件事

2022年刚开始有了向要跳槽的想法,之前的公司不能算大厂但在重庆也算是数一数二。开始跳槽的的时候我其实挺犹豫的 其实说是有跳槽的想法在2022年过年的时候就有了,因为每年公司3月会有涨薪的机会,所以想着看看那能不能涨(其实还是…...

从GPT到GPT-3:自然语言处理领域的prompt方法

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...

Git代码提交规范

Git 代码规范Git 每次提交代码,都是需要写 Commit message(提交说明),否则就不允许提交。Commit message 的格式 (三部分):Heaher ----- 必填type ---必需scope --- 可选subject --- 必需Body ---- 可省略Footer ---- …...

【JavaScript速成之路】JavaScript内置对象--Math和Date对象

📃个人主页:「小杨」的csdn博客 🔥系列专栏:【JavaScript速成之路】 🐳希望大家多多支持🥰一起进步呀! 文章目录前言1,Math对象1.1,常用属性方法1.1.1,获取x的…...

(自用POC)Fortinet-CVE-2022-40684

本文转载于:https://mp.weixin.qq.com/s?__bizMzIzNDU5Mzk2OQ&mid2247485332&idx1&sn85931aa474f1ae2c23a66bf6486eec63&chksme8f54c4adf82c55c44bc7b1ea919d44d377e35a18c74f83a15e6e20ec6c7bc65965dbc70130d&mpshare1&scene23&srcid…...

ConvNeXt V2实战:使用ConvNeXt V2实现图像分类任务(二)

文章目录训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整算法设置混合精度,DP多卡,EMA定义训练和验证函数训练函数验证函数调用训练和验证方法运行以及结果查看测试热力图可视化展示完…...

【人工智能与深度学习】基于正则化潜在可变能量的模型

【人工智能与深度学习】基于正则化潜在可变能量的模型 正则化潜变量能量基础模型稀疏编码FISTALISTA稀疏编码示例卷积稀疏编码自然图像上的卷积稀疏编码可变自动编码器正则化潜变量能量基础模型 具有潜在变量的模型能够生成预测分布 y ‾ \overline{y}...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子&#xff08…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言:多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

【kafka】Golang实现分布式Masscan任务调度系统

要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...