当前位置: 首页 > 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}...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

数据链路层的主要功能是什么

数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

Python如何给视频添加音频和字幕

在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...