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

JavaSec-RCE

简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性&#xff0c…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...