Web API 基础 (Web Workers API)

2023-10-10 18:01
文章标签 基础 web api workers

本文主要是介绍Web API 基础 (Web Workers API),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Web Workers API

1、指南

1.1 使用Web Workers

Web Workers是一种让Web内容在后台线程中运行脚本的简单方法。工作线程可以在不干扰用户界面的情况下执行任务。此外,它们还可以使用XMLHttpRequest(尽管responseXMLchannel属性总是为空)或fetch(没有此类限制)执行I/O。工作线程一旦被创建,就可以通过向JavaScript代码指定的事件处理程序发送消息来向创建它的JavaScript代码发送消息(反之亦然)。

本文详细介绍了如何使用web worker。

1.1.1 Dedicated workers

如上所述,Dedicated worker只能由调用它的脚本访问。在本节中,我们将讨论在 Basic dedicated worker example示例中发现的JavaScript:它允许您输入两个要相乘的数字。这些数字被发送给一个专门的工作者,相乘,结果返回到页面并显示。

这个示例相当简单,但我们决定在向您介绍基本的worker概念时保持简单。本文稍后将介绍更高级的细节。

Worker feature detection

为了更好地控制错误处理和向后兼容性,将 worker 访问代码包装在下面(main.js)中是一个好主意:

if (window.Worker) {// …
}
Spawning a dedicated worker

创建一个新的worker很简单。您所需要做的就是调用Worker()构造函数,指定要在Worker线程中执行的脚本的URI

// main.js
const myWorker = new Worker("worker.js");
向专用worker发送和从专用worker发送消息

worker的魔力是通过postMessage()方法和onmessage事件处理程序实现的。当您想要向worker发送消息时,您可以像这样向它发送消息

first.onchange = () => {myWorker.postMessage([first.value, second.value]);console.log("Message posted to worker");
};second.onchange = () => {myWorker.postMessage([first.value, second.value]);console.log("Message posted to worker");
};

这里有两个<input>元素分别由变量firstsecond表示;当其中一个的值被改变时,myWorker.postMessage([first.value,second.value])被用来将两者中的值以数组的形式发送给worker。你可以在消息中发送任何你喜欢的东西。

在worker中,当收到消息时,我们可以通过编写这样的事件处理程序块来响应:

// worker.js
onmessage = (e) => {console.log("Message received from main script");const workerResult = `Result: ${e.data[0] * e.data[1]}`;console.log("Posting message back to main script");postMessage(workerResult);
};

onmessage处理程序允许我们在接收到消息时运行一些代码,消息本身在message 事件的data属性中可用。这里我们将两个数字相乘,然后再次使用postMessage(),将结果发送回主线程。

回到主线程,我们再次使用onmessage来响应从worker发送回来的消息:

myWorker.onmessage = (e) => {result.textContent = e.data;console.log("Message received from worker");
};

这里我们获取消息事件数据并将其设置为result段落的textContent,这样用户就可以看到计算的结果。

结束 worker

如果你需要在主线程中立即终止一个正在运行的worker,你可以通过调用worker的terminate方法来完成:

myWorker.terminate();

工作线程被立即终止。

处理错误

当工作线程中发生运行时错误时,将调用其onerror事件处理程序。它接收一个名为error的事件,该事件实现了ErrorEvent接口。

事件不会冒泡并且可以取消;为了防止默认操作发生,worker可以调用错误事件的preventDefault()方法。

错误事件有以下三个感兴趣的字段:

  • message
    一个人类可读的错误信息。
  • filename
    发生错误的脚本文件的名称。
  • lineno
    发生错误的脚本文件的行号。
Spawning subworkers

如果workers 愿意,他们可能会产生更多的workers 。所谓的子worker必须托管在与父页面相同的源中。此外,子worker的uri是相对于父worker的位置而不是所属页面的位置进行解析的。这使得workers 更容易跟踪他们的依赖项在哪里。

导入脚本和库

工作线程可以访问全局函数importScripts(),该函数允许它们导入脚本。它接受零个或多个uri作为要导入的资源的参数;以下所有例子都是正确的:

importScripts(); /* imports nothing */
importScripts("foo.js"); /* imports just "foo.js" */
importScripts("foo.js", "bar.js"); /* imports two scripts */
importScripts("//example.com/hello.js",
); /* You can import scripts from other origins */

浏览器加载列出的每个脚本并执行它。然后,worker可以使用每个脚本中的任何全局对象。如果无法加载脚本,则抛出NETWORK_ERROR,并且不会执行后续代码。之前执行的代码(包括使用setTimeout()延迟的代码)仍然可以使用。还保留了importScripts()方法之后的函数声明,因为它们总是在其余代码之前求值。

1.1.2 Shared workers

一个共享的工作线程可以被多个脚本访问——即使它们被不同的窗口、iframe甚至工作线程访问。在本节中,我们将讨论基 Basic shared worker example示例中的JavaScript(运行shared worker):这与basic dedicated worker 示例非常相似,除了它有两个可用的函数,由不同的脚本文件处理:两个数字的乘法,或一个数字的平方。两个脚本都使用同一个worker来执行所需的实际计算。

在这里,我们将集中讨论 dedicated workers 和shared workers之间的区别。请注意,在这个示例中,我们有两个HTML页面,每个页面都应用了使用相同工作文件的JavaScript。

生成一个 shared worker

生成一个新的共享工作线程与 dedicated 工作线程非常相似,但使用不同的构造函数名称(参见index.htmlindex2.html) -每个构造函数都必须使用如下代码启动工作线程:

const myWorker = new SharedWorker("worker.js");

一个很大的区别是,对于共享工作线程,您必须通过port 对象进行通信—打开一个显式端口,脚本可以使用该端口与工作线程进行通信(这在 dedicated 工作线程的情况下隐式完成)。

端口连接需要通过使用onmessage事件处理程序隐式启动,或者在发布任何消息之前显式地使用start()方法启动。只有当消息事件通过addEventListener()方法连接时才需要调用start()

注意:当使用start()方法打开端口连接时,如果需要双向通信,则需要从父线程和工作线程都调用该方法。

向共享worker发送消息和从共享worker发送消息

现在消息可以像以前一样发送到worker,但是postMessage()方法必须通过port对象调用(同样,你会在 multiply.jssquare.js中看到类似的结构):

// square.js/multiply.js
squareNumber.onchange = () => {myWorker.port.postMessage([squareNumber.value, squareNumber.value]);console.log("Message posted to worker");
};

现在,来看看worker。这里也有一点复杂

onconnect = (e) => {const port = e.ports[0];port.onmessage = (e) => {const workerResult = `Result: ${e.data[0] * e.data[1]}`;port.postMessage(workerResult);};
};

首先,当端口连接发生时,我们使用onconnect处理程序来触发代码(例如,当父线程中的onmessage事件处理程序被设置时,或者当父线程中显式调用start()方法时)。

我们使用该事件对象的ports属性来获取端口并将其存储在一个变量中。

接下来,我们在端口上添加一个onmessage处理程序来执行计算并将结果返回给主线程。在工作线程中设置这个onmessage处理程序也会隐式地打开到父线程的端口连接,因此实际上不需要调用port.start(),如上所述。

最后,回到主脚本,我们处理消息(同样,您将在multi .js和square.js中看到类似的结构)。

// multiply.js and square.js
myWorker.port.onmessage = (e) => {result2.textContent = e.data;console.log("Message received from worker");
};

当消息通过端口从worker返回时,我们将计算结果插入到适当的结果段落中。

1.2 Web worker可用的函数和类

除了标准的JavaScript函数集(如StringArrayObjectJSON等)之外,还有各种各样的函数可以从DOM中提供给worker。本文提供了一个列表。

Worker Contexts & Functions

工作线程运行在与当前窗口(window)不同的全局上下文中!虽然Window不是直接对worker可用,但许多相同的方法都是在一个共享的mixin (WindowOrWorkerGlobalScope)中定义的,并且通过worker自己的WorkerGlobalScope派生的上下文提供给worker使用:

  • DedicatedWorkerGlobalScope for dedicated workers
  • SharedWorkerGlobalScope for shared workers
  • ServiceWorkerGlobalScope for service workers

一些函数(一个子集)是所有工作线程和主线程(来自WindowOrWorkerGlobalScope)共同的:

  • atob()
  • btoa()
  • clearInterval()
  • clearTimeout()
  • dump() Non-standard
  • queueMicrotask()
  • setInterval()
  • setTimeout()
  • structuredClone()
  • window.requestAnimationFrame (dedicated workers only)
  • window.cancelAnimationFrame (dedicated workers only)

以下函数仅对worker可用:

  • WorkerGlobalScope.importScripts() (all workers)
  • DedicatedWorkerGlobalScope.postMessage (dedicated workers only)

worker中可用的Web APIs

注意:如果列出的API在特定版本中被平台支持,那么通常可以认为它在web worker中可用。您还可以使用网站https://worker-playground.glitch.me/测试对特定对象/函数的支持

1.3 结构化克隆算法

结构化克隆算法复制复杂的JavaScript对象。它在调用structuredClone()时内部使用,通过postMessage()在 worker 之间传输数据,使用IndexedDB存储对象,或为其他api复制对象。

它通过递归遍历输入对象进行克隆,同时维护以前访问过的引用的映射,以避免无限遍历循环。

结构化克隆不适用的东西

  • 函数对象不能被结构化克隆算法复制;试图抛出DataCloneError异常。
  • 克隆 DOM 节点同样会抛出DataCloneError异常。
  • 某些对象属性不保留:
    • 不保留RegExp对象的lastIndex属性。
    • 属性描述符、setter、getter和类似元数据的特性不复制。例如,如果一个对象用属性描述符标记为只读,那么它将在副本中被读/写,因为这是默认的。
    • 原型链(prototype chain)不会被遍历或复制。

支持的类型

JavaScript types
Error types
Web/API types

1.4 Transferable objects

可转移对象(Transferable objects)是拥有资源的对象,这些资源可以从一个上下文中转移到另一个上下文中,从而确保资源一次只在一个上下文中可用。转移后,原对象不再可用;它不再指向传输的资源,并且任何读取或写入该对象的尝试都会抛出异常。

可转移对象通常用于共享一次只能安全地暴露给单个JavaScript线程的资源。例如,ArrayBuffer是一个可转移的对象,它拥有一块内存。当这样的缓冲区在线程之间传输时,相关的内存资源将从原始缓冲区中分离出来,并附加到新线程中创建的缓冲区对象上。原始线程中的缓冲区对象不再可用,因为它不再拥有内存资源。

在使用structuredClone()创建对象的深度拷贝时也可能使用Transferring 。克隆操作之后,转移的资源将被移动,而不是复制到克隆对象中。

用于传输对象资源的机制取决于对象本身。例如,当在线程之间传输ArrayBuffer时,它所指向的内存资源实际上是在上下文之间以快速有效的零复制操作移动的。其他对象可以通过复制相关资源然后从旧上下文中删除来传输。

并不是所有的对象都是可转移的。下面提供了可转移对象的列表。

在线程之间传输对象

下面的代码演示了将消息从主线程发送到web worker线程时传输是如何工作的。Uint8Array在工作中被复制(复制),而它的缓冲区被转移。传输后,从主线程读取或写入uInt8Array的任何尝试都会抛出,但您仍然可以检查byteLength以确认它现在为零。

// Create an 8MB "file" and fill it. 8MB = 1024 * 1024 * 8 B
const uInt8Array = new Uint8Array(1024 * 1024 * 8).map((v, i) => i);
console.log(uInt8Array.byteLength); // 8388608// Transfer the underlying buffer to a worker
worker.postMessage(uInt8Array, [uInt8Array.buffer]);
console.log(uInt8Array.byteLength); // 0

注意:类型化数组,如Int32ArrayUint8Array,是可序列化的,但不可转移。然而,它们的底层缓冲区是ArrayBuffer,这是一个可转移的对象。我们可以在data参数发送uInt8Array.buffer。而不是传输数组中的uInt8Array

克隆操作期间的转移

下面的代码显示了structuredClone()操作,其中底层缓冲区从原始对象复制到克隆对象。

const original = new Uint8Array(1024);
const clone = structuredClone(original);
console.log(original.byteLength); // 1024
console.log(clone.byteLength); // 1024original[0] = 1;
console.log(clone[0]); // 0// Transferring the Uint8Array would throw an exception as it is not a transferable object
// const transferred = structuredClone(original, {transfer: [original]});// We can transfer Uint8Array.buffer.
const transferred = structuredClone(original, { transfer: [original.buffer] });
console.log(transferred.byteLength); // 1024
console.log(transferred[0]); // 1// After transferring Uint8Array.buffer cannot be used.
console.log(original.byteLength); // 0

Supported objects

注意:可转移对象在Web IDL文件中被标记为属性[Transferable]

2、接口

2.1 DedicatedWorkerGlobalScope

可以通过self关键字访问DedicatedWorkerGlobalScope对象(Worker全局作用域)。JavaScript Reference中列出了一些额外的全局函数、命名空间对象和构造函数,它们通常不与worker全局作用域关联,但在它上可用。参见:Functions available to workers.。
在这里插入图片描述

2.2 ServiceWorker

2.3 SharedWorker

2.4 SharedWorkerGlobalScope

2.5 Worker

Web Workers API 的Worker接口代表了一个可以通过脚本创建的后台任务,它可以将消息发送回它的创建者。

通过调用Worker("path/to/worker/script")构造函数来创建 worker。

Workers 可以自己产生新的Workers ,只要这些Workers 被托管在与父页相同的origin。

并不是所有的接口和函数都对 Worker中 的脚本可用。Workers 可以使用XMLHttpRequest进行网络通信,但是它的responseXMLchannel属性总是为null。(fetch也是可用的,没有这样的限制。)

在这里插入图片描述

构造函数

Worker()

创建一个专用(dedicated)的web worker,执行指定的URL处的脚本。这也适用于 Blob URLs。该脚本必须遵守同源策略。

注意:浏览器制造商对于数据URL是否同源存在分歧。虽然Firefox 10及以后的版本接受数据url,但并非所有其他浏览器都是如此。

new Worker(aURL)
new Worker(aURL, options)
  • aURL
    一个字符串,表示工作线程将要执行的脚本的URL。它必须遵守同源策略。

  • options 可选
    一个对象,其中包含可在创建对象实例时设置的选项属性。可用的属性如下:

    • type
      指定要创建的工作线程类型的字符串。取值为classicmodule。如果未指定,则使用的默认值为classic

    • credentials
      指定工作线程使用的凭据类型的字符串。该值可以是omitsame-origininclude。如果没有指定,或者如果type是classic,则默认使用omit (不需要凭据)。

    • name
      一个字符串,指定用于表示工作器范围的DedicatedWorkerGlobalScope的标识名,主要用于调试目的。

实例方法

  • Worker.postMessage()
    发送一个消息——由任何JavaScript对象组成——到worker的内部作用域。

Worker postMessage()方法委托给MessagePort postMessage()方法,该方法在事件循环中添加一个与接收MessagePort相对应的任务。

Worker可以使用DedicatedWorkerGlobalScope.postMessage方法将信息发送回生成它的线程。

postMessage(message)
postMessage(message, options)
postMessage(message, transfer)
  • message
    交付给worker的对象;这将在交付给DedicatedWorkerGlobalScope.message_event 事件的data 字段中。这可以是由结构化克隆算法处理的任何值或JavaScript对象,其中包括循环引用。
    如果没有提供消息参数,解析器将抛出SyntaxError。如果要传递给worker的数据不重要,则可以显式传递nullundefined

  • options 可选
    一个可选对象,它包含一个transfer 字段,该字段包含一组要传输其所有权的可传输对象。如果对象的所有权被转移,它将在发送它的上下文中变得不可用,并且只对发送它的 worker 可用。

  • transfer 可选
    可转移对象的可选数组,用于转移其所有权。如果对象的所有权被转移,它将在发送它的上下文中变得不可用,并且只对发送它的worker 可用。
    可转移对象是类的实例,如ArrayBuffer, MessagePort或ImageBitmap对象可以被转移。null不是可接受的transfer值。

注意: postMessage()一次只能发送一个对象。如上所示,如果你想传递多个值,你可以发送一个数组。

  • Worker.terminate()
    立即终止 worker。这不会让worker完成它的操作;它立刻停止了。ServiceWorker实例不支持此方法。

事件

  • error
    在工作线程中发生错误时触发。

  • message
    当worker的父进程收到来自该worker的消息时触发。

  • messageerror
    当Worker对象接收到无法反序列化的消息时触发。

  • rejectionhandled
    每次Promise被拒绝时触发,不管是否有处理程序来捕获拒绝。

  • unhandledrejection
    当Promise拒绝而没有处理程序捕获拒绝时触发。

Example

下面的代码片段使用Worker()构造函数创建一个Worker对象,然后使用该Worker对象:

const myWorker = new Worker("/worker.js");
const first = document.querySelector("input#number1");
const second = document.querySelector("input#number2");first.onchange = () => {myWorker.postMessage([first.value, second.value]);console.log("Message posted to worker");
};

有关完整示例,请参阅我们的 Basic dedicated worker example

2.6 WorkerGlobalScope

Web Workers API的WorkerGlobalScope接口是一个表示任何worker的作用域的接口。Workers 没有浏览器上下文;这个范围包含通常由Window对象传递的信息——在本例中是事件处理程序、控制台或相关的WorkerNavigator对象。每个WorkerGlobalScope都有自己的事件循环。

这个接口通常被每个worker类型特例化:dedicated worker的专用 DedicatedWorkerGlobalScope , shared worker的共享SharedWorkerGlobalScope, ServiceWorker的ServiceWorkerGlobalScope。self属性返回每个上下文的专用范围。

在这里插入图片描述

Example

你不能在代码中直接访问WorkerGlobalScope;然而,它的属性和方法是由更具体的全局作用域继承的,比如DedicatedWorkerGlobalScopeSharedWorkerGlobalScope。例如,你可以将另一个脚本导入到worker中,并使用以下两行打印出worker作用域的导航器对象的内容:

importScripts("foo.js");
console.log(navigator);

2.7 WorkerLocation

WorkerLocation接口定义了Worker执行的脚本的绝对位置。这样的对象为每个worker初始化,并通过WorkerGlobalScope可用。通过调用self.location获得的Location属性。

2.8 WorkerNavigator

WorkerNavigator接口表示允许从 Worker 访问的Navigator接口的一个子集。这样的对象为每个Worker初始化,并通过self.navigator属性可用。

在这里插入图片描述

这篇关于Web API 基础 (Web Workers API)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/182148

相关文章

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Java Web指的是什么

Java Web指的是使用Java技术进行Web开发的一种方式。Java在Web开发领域有着广泛的应用,主要通过Java EE(Enterprise Edition)平台来实现。  主要特点和技术包括: 1. Servlets和JSP:     Servlets 是Java编写的服务器端程序,用于处理客户端请求和生成动态网页内容。     JSP(JavaServer Pages)

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

9.8javaweb项目总结

1.主界面用户信息显示 登录成功后,将用户信息存储在记录在 localStorage中,然后进入界面之前通过js来渲染主界面 存储用户信息 将用户信息渲染在主界面上,并且头像设置跳转,到个人资料界面 这里数据库中还没有设置相关信息 2.模糊查找 检测输入框是否有变更,有的话调用方法,进行查找 发送检测请求,然后接收的时候设置最多显示四个类似的搜索结果

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

【LabVIEW学习篇 - 21】:DLL与API的调用

文章目录 DLL与API调用DLLAPIDLL的调用 DLL与API调用 LabVIEW虽然已经足够强大,但不同的语言在不同领域都有着自己的优势,为了强强联合,LabVIEW提供了强大的外部程序接口能力,包括DLL、CIN(C语言接口)、ActiveX、.NET、MATLAB等等。通过DLL可以使用户很方便地调用C、C++、C#、VB等编程语言写的程序以及windows自带的大