Web Worker 学习及使用

news2024/12/25 12:25:56

了解什么是 Web Worker

提供了可以在后台线程中运行 js 的方法。可以不占用主线程,不干扰用户界面,可以用来执行复杂、耗时的任务。

worker中运行的是另一个全局上下文,不能直接获取 Window 全局对象。不同的 worker 可以分为专用和共享,专用 worker 仅在单一脚本中被使用,它的上下文对象是DedicatedWorkerGlobalScope;共享 worker 可以同时被多个脚本占用,它的上下文对象是SharedWorkerGlobalScope

Worker中可以使用什么,不可以使用什么,只要不影响主线程,就可以使用。

  • 不能直接操作 DOM
  • 不能访问 Window 对象的默认方法和属性
  • 可以访问并使用 Window 下的其他 API 对象,比如:websocket、indexDB、Navigator、XMLHttpRequest 等

worker和主线程之间通过postMessage发送消息,使用onmessage事件来监听收到的消息。交互过程中的数据是被复制传输的。

检测当前浏览器环境中是否支持worker

if (window.Worker) {
  // ...
}

测试生成大量的数据并排序,模拟耗时的任务。

console.log("执行任务1");
let start = performance.now();

let arr = [];
for (let i = 0; i < 1000000; i++) {
  let num = Math.random() * 10000;
  arr.push(num);
}
arr.sort();

let end = performance.now();

console.log("耗时-----", end - start);

console.log("执行任务2");

在这里插入图片描述

任务 2 被中间的耗时任务占用了主线程,等待耗时任务执行完才去执行。这样就造成了任务 2 的延后,得不到任务 2 的及时响应反馈。我们使用 worker 来解决,将这种任务放到其他线程去执行,最后只需要拿到结果就行。

专用Worker

创建一个work.js,将耗时任务放到这个 js 中。并通过postMessage向主线程发送消息。

// ...耗时任务

postMessage(arr);

在主线程中调用 work.js,并接收来自 work 的数据。

console.log("执行任务1");

let work = new Worker("./work.js");
work.onmessage = (e) => {
  // ...
  console.log("来自worker的数据:", e.data.length);
};

console.log("执行任务2");

在这里插入图片描述

放入Worker的耗时任务不会影响主线程其他任务执行,可以看到任务 1/2 很快执行完。主线程接收来自 worker 的数据,本质意义是让这些任务不要在主线程中执行,那么前端采用worker增加线程去执行,也可以直接将任务甩给后台去执行,在通过接口拿到结果。

worker 执行完毕后,如不使用则可以主动关闭。通过worker.terminate()调用方法终止线程,方法调用不会等待 worker 完成它剩余的任务。

错误处理,通过监听onerror监听 worker 运行中的错误.

错误事件参数包含:

  • message 错误消息
  • filename 发生错误的脚本文件
  • lineno 发生错误所在脚本文件的代码位置

如果 worker 接收到一条无法被反序列化的消息时,将在对象上触发messageerror事件。

所有的事件也可以通过对象方法addEventListener去监听。

嵌套Worker

在一个 worker 中仍然可以调用另一个 worker。子 worker 解析的 URI 是相对父 worker 的地址而不是自身地址;它们必须托管在同源的父页面内。

创建一个subWorker.js,加入同样的代码,在worker.js中调用

// sub worker
let worker = new Worker("./subWork.js");

let start = performance.now();
// ... 耗时任务
let end = performance.now();

console.log("耗时-----", end - start);
worker.onmessage = (e) => {
  console.log("sub worker数据:", e.data.length);
};

postMessage(arr);

在父 worker 中的耗时任务则会堵塞后续代码的执行,导致实际上子 worker 可能已经执行完了,但由于worker.onmessage在后面执行,导致迟迟拿不到结果,这就需要对于复杂并行的任务需要有一个很好的调度,以便更快拿到不受其他任务影响的当前任务的执行结果。

加载脚本

在 worker 中通过importScripts来加载第三方脚本,它可以接受多个参数来引入多个资源。

浏览器会并行列加载每一个脚本,每个脚本中的全局对象可以被 worker 使用。如果脚本加载失败,则抛出异常,停止后面代码的执行。importScripts 会等待所有脚本加载执行完毕才会继续执行,

可以利用 worker 加载前端的一些资源然后利用浏览器的缓存,主线程再去请求加载时则可以直接使用缓存。从而加快主线程的页面渲染;

我们提供一个utils.js函数,在work.js中加载后调用里面的方法

importScripts("./utils.js");

// ...

postMessage(add(2, 3));

在成功加载utils.js后,worker 就可以使用add()方法了。importScripts 加载的脚本是同步执行的,因此可以放心使用。

共享Worker

可以被多个脚本使用,即使这些脚本是被不同的 window、iframe 或者作为子 worker 访问。共享的 worker 必须是同源的,不能跨域。

共享 worker 一个最大的区别就是与脚本之间的通信必须通过port属性,它是一个确切打开的端口供脚本与 worker 通信,这在专用 worker 是隐形的。

通过SharedWorker来创建共享 worker,我们在创建一个 htmltest.html,和之前的index.html一样,让它们共享work.js

在页面中,重新创建共享 worker 加载 share-worker.js

console.log("执行任务1");

let work = new SharedWorker("./share-worker.js");
work.port.onmessage = (e) => {
  // ...
  console.log("来自worker的数据:", e.data.length);
};

console.log("执行任务2");

然后在share-worker.js中发送数据

// ...

onconnect = (e) => {
  const port = e.ports[0];

  port.postMessage(e);
};

结构化克隆算法

worker 在于脚本通信的时候,数据值复制的,而不是共享的。这里是用到了结构化克隆算法,有几个注意的地方:

  1. Function 不能被克隆,会抛出DATA_CLONE_ERR异常
  2. DOM 节点不被允许克隆,抛出异常
  3. 对象的某些参数不被保留,比如:RegExp 对象的 lastIndex 字段不会被保留;属性描述符;原型链上的属性

全局的structuredClone()使用了结构化算法克隆对象,它是一种深拷贝,而且它还支持把可转移对象转移到新对象。就是将可转移对象与原对象分离,然后附加到新对象上。

可转移对象:ArrayBuffer \ MessagePort \ ReadableStream \ WritableStream \ TransformStream \ AudioData \ ImageBitmap \ VideoFrame \ OffscreenCanvas \ RTCDataChannel

里面就ArrayBuffer使用过,其他都没用过,做一个测试

let buffer = new ArrayBuffer(8);
console.log("buffer:", buffer.byteLength);

// 普通克隆
let newBuffer = structuredClone(buffer);
console.log("buffer:", buffer.byteLength, "newBuffer:", newBuffer.byteLength);

这时仅是数据的复制,原对象buffer的长度还在。使用对象转移拷贝:

let newBuffer = structuredClone(buffer, { transfer: [buffer] });

原对象还可以访问,只是分配占用的内存没有了,它已经转移给新对象了。structuredClone还可以处理循环引用

在这里插入图片描述

所以在 worker 之间传输可转移对象,效率是非常快的。当然这样就导致在主线程中不能再使用原始对象访问数据。

需要在脚本和 worker 之间转移对象,需要增加postMessage第二个参数:数组列出需要转移的对象

// ... 脚本其他任务
work.postMessage(buffer, [buffer]);

Worker API

创建Worker时,除了第一个参数为脚本的 URL,还接受第二个参数options,包含:

  • type worker 类型,默认classic,可指定module
  • credentials 凭证,可以是omit \ same-origin \ include,未制定默认是omit(不要求凭证)
  • name worker 名称,用于调试。

Worker中有自己的全局作用域,通过self访问,专用 worker 为DedicatedWorkerGlobalScope,包含了全局函数、命名空间以及构造器。除了name属性其余都继承于WorkerGlobalScope

  • name 创建 worker 时设置的名称。
  • console 返回与当前 worker 相关联的 Console
  • location 返回与当前 worker 相关联的WorkerLocation(是浏览器 Location 的子级,适配了 worker)
  • navigator返回与当前 worker 相关联的WorkerNavigator(是浏览器 Navigator 的子级,适配了 worker)
  • performance 返回与当前 worker 相关联的 performance

实现了来自WindowTimers \ WindowBase64的方法,可以使用atob \ btoa \ setInterval \ setTimeout方法等。

共享 worker 的全局对象为SharedWorkerGlobalScope,它也是继承自WorkerGlobalScope

其他类型的Worker

除了Worker,还有其他的一些 workder。

Service Worker可作为代理服务器,目的是创建有效的离线体验,可以拦截网络请求、缓存网路资源,并根据网络采取合适的行动,比如导航到不同的服务器。结合Push API可以实现离线消息推送,即使用户没有打开当前应用,也能及时收到消息。

Audio Worklet 用于处理音频数据,它允许开发者在音频工作线程中运行 JavaScript 代码。实时音频效果处理,合成器等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1865048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Vue Router 的 meta 属性实现多种功能

在 Vue.js 中&#xff0c;Vue Router 提供了强大的路由管理功能。通过 meta 属性&#xff0c;我们可以在路由定义中添加自定义元数据&#xff0c;以实现访问控制、页面标题设置、角色权限管理、页面过渡效果等多种功能。本文将总结如何使用 meta 属性来实现这些常见的功能。 1.…

gici-open学习日记(7):GNSS图优化——RTK

gici-open学习日记——GNSS RTK图优化 前言初始化RTK的调用rearrangePhasesAndCodes双差构造formPhaserangeDDPair周跳探测cycleSlipDetectionSD添加参数块模糊度参数部分addSdAmbiguityParameterBlocks添加双差伪距残差addDdPseudorangeResidualBlocks添加双差相位残差addDdPh…

springcloud-gateway 路由加载流程

问题 Spring Cloud Gateway版本是2.2.9.RELEASE&#xff0c;原本项目中依赖服务自动发现来自动配置路由到微服务的&#xff0c;但是发现将spring.cloud.gateway.discovery.locator.enabledfalse 启动之后Gateway依然会将所有微服务自动注册到路由中&#xff0c;百思不得其解&a…

手把手从零开始搭建远程访问服务

远程访问服务工具——FRP frp 是一个能够实现内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网的服务器来转发。 资源链接 根据自己服务型号和操作系统来选取对应的文件&#xff0c;不知道的…

汽车EDI: BMW EDI项目案例

宝马集团是全世界成功的汽车和摩托车制造商之一&#xff0c;旗下拥有BMW、MINI和Rolls-Royce三大品牌&#xff1b;同时提供汽车金融和高档出行服务。作为一家全球性公司&#xff0c;宝马集团在14个国家拥有31家生产和组装厂&#xff0c;销售网络遍及140多个国家和地区。 本文主…

mitt通信

一、mitt介绍 mitt是一款轻量级的组件通信插件(大小仅为200字节左右) 二、mitt安装 npm install --save mitt三、使用 1.在组件中使用 import mitt from mitt //创建mitt实例 const emitter mitt()// 监听事件 emitter.on(foo, e > console.log(foo, e) )// 通过通配符监…

09. Java ThreadLocal 的使用

1. 前言 本节内容主要是对 ThreadLocal 进行深入的讲解&#xff0c;具体内容点如下&#xff1a; 了解 ThreadLocal 的诞生&#xff0c;以及总体概括&#xff0c;是学习本节知识的基础&#xff1b;了解 ThreadLocal 的作用&#xff0c;从整体层面理解 ThreadLocal 的程序作用&…

VC++开发积累——vc++6.0中删除函数的方法,右键,Delete

目录 引出插曲&#xff1a;删除函数的方法多行注释的实现代码输入的自动提示搜索出来&#xff0c;标记和取消标记跳转到上一步的位置 ctrl TAB 总结其他规范和帮助文档创建第一个Qt程序对象树概念信号signal槽slot自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进行触发 自…

千呼新零售2.0-OCR拍照识别采购单

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物、中医养生、大健康等连锁店…

Python 实现Excel转TXT,或TXT文本导入Excel

Excel是一种具有强大的数据处理和图表制作功能的电子表格文件&#xff0c;而TXT则是一种简单通用、易于编辑的纯文本文件。将Excel转换为TXT可以帮助我们将复杂的数据表格以文本的形式保存&#xff0c;方便其他程序读取和处理。而将TXT转换为Excel则可以将文本文件中的数据导入…

AI引领创意潮流:高效生成图片,参考图助力,一键保存到指定文件夹

在这个数字与创意交融的时代&#xff0c;我们迎来了AI绘画的新纪元。借助先进的AI技术&#xff0c;我们不仅能够高效生成图片&#xff0c;还能在参考图的启发下&#xff0c;激发无限创意&#xff0c;让您的想象力在数字世界中自由翱翔。 首助编辑高手软件中的魔法智能绘图板块&…

PMP证书在国内已经泛滥了,大家怎么看?

目前&#xff0c;越来越多的人获得了PMP证书。自1999年PMP引入中国以来&#xff0c;全国累计PMP考试人数接近60万人次&#xff0c;通过PMP认证的人数约为42万人。虽然这个数据看起来很大&#xff0c;但绝对不能说是过多。 首先&#xff0c;PMP在中国并不普遍。根据美国项目管理…

解决go语言对接s3的SDK上传文件遇到的问题

先看正确的配置 问题1 配置文件中的OssEndpoint 不管是minio还是oss需要带上http://或者https:// 否则会出现这个问题 operation error S3: PutObject, exceeded maximum number of attempts, 3, https response error StatusCode: 0, RequestID: , HostID: , request send …

qt报错:“QtRunWork”任务返回了 false,但未记录错误。

qt报错&#xff1a;“QtRunWork”任务返回了 false&#xff0c;但未记录错误。 说明情况一 说明 这个报错可能的原因有很多&#xff0c;这里只写一种&#xff0c;以后遇到再进行补充。 情况一 如果 Q_OBJECT 宏未正确处理&#xff0c;通常会出现类似的错误。 要使用信号与槽…

视频汇聚平台LntonCVS视频集中存储平台技术解决方案

安防视频监控技术是一种利用各种监控设备捕捉实时画面&#xff0c;并将其传输至监控中心或数据存储设备的技术。随着科技的不断进步&#xff0c;监控视频技术也在不断改进&#xff0c;应用领域也在不断扩展。 然而&#xff0c;尽管技术进步&#xff0c;当前视频监控技术仍然面临…

PointCloudLib-特征(Features)-全局对齐空间分布 (GASD) 描述符

全局对齐空间分布 (GASD) 描述符 本文档介绍用于高效对象识别和姿势估计的全局对齐空间分布 ([GASD]) 全局描述符。 GASD 基于对表示对象实例的整个点云的参考系的估计,该参考系用于将其与规范坐标系对齐。之后,根据对齐点云的 3D 点的空间分布方式计算对齐点云的描述符…

最新!计算机类SCI期刊全名单!你想发的顶刊都在这里

【SciencePub学术】近日&#xff0c;2023JCR正式发布&#xff0c;最受瞩目就是各类期刊的最新影响因子排名&#xff0c;本期&#xff0c;小编对计算机类的期刊做了一个整理&#xff0c;供计算机方向的研究学者们参考&#xff01; 来源&#xff1a;WOS数据库官网 完整名单 ※ 本…

新手选择代理IP时这几点误区一定要避开!

在选择代理IP时&#xff0c;许多用户可能会因为对代理IP的认识不足或受到一些误导&#xff0c;而陷入一些常见的误区。这些误区不仅可能导致用户无法达到预期的效果&#xff0c;还可能带来一些不必要的风险。下面&#xff0c;IPIDEA代理IP就与大家一同分析在选择代理IP时需要避…

《Attention is all you need》通俗解读,彻底理解版:part1

最近在更新 Transformer 的技术专栏&#xff0c;如果你关注我的公众号的话&#xff0c;会发现有不少文章都打上了“Transformer最后一公里”的标签。 打上标签的文章要么是介绍 Transformer 技术的&#xff0c;要么是介绍学习Transformer 所需要的背景知识的&#xff0c;比如这…

typescript学习回顾(二)

今天来分享一下ts的基础&#xff0c;如何使用ts&#xff0c;以及ts具体的作用&#xff0c;如何去约束我们开发中常见的一些数据的&#xff0c;最后做一个小练习来巩固对ts基础的掌握程度。 类型约束 如何加类型约束呢 变量、函数的参数、函数的返回值位置加上:类型 比如 //约…