网页
综合
更新时间 2025-03-14 06:14:58
使用 Web Worker - Web API | MDN
自动蜘蛛
developer.mozilla.org
正文约 3555 字
HTML: Markup language
CSS: Styling language
JavaScript: Scripting language
Web APIs: Programming interfaces
Learn web development
Get to know MDN better
此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。
View in English Always switch to English
Web Worker 为 Web 内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,它们可以使用 XMLHttpRequest(尽管 responseXML 和 channel 属性总是为空)或 fetch(没有这些限制)执行 I/O。一旦创建,一个 worker 可以将消息发送到创建它的 JavaScript 代码,通过将消息发布到该代码指定的事件处理器(反之亦然)。
本文详细介绍了如何使用 web worker。
一个 worker 是使用一个构造函数创建的一个对象(例如 Worker())运行一个命名的 JavaScript 文件——这个文件包含将在 worker 线程中运行的代码; worker 运行在另一个全局上下文中,不同于当前的window。因此,在 Worker 内通过 window 获取全局作用域(而不是self)将返回错误。
在专用 worker 的情况下,DedicatedWorkerGlobalScope 对象代表了 worker 的上下文(专用 worker 是指标准 worker 仅在单一脚本中被使用;共享 worker 的上下文是 SharedWorkerGlobalScope 对象)。一个专用 worker 仅能被首次生成它的脚本使用,而共享 worker 可以同时被多个脚本使用。
备注:参见 Web Worker API 落地页以获取 worker 的参考文档和更多指引。
在 worker 线程中你可以运行任何你喜欢的代码,不过有一些例外情况。比如:在 worker 内,不能直接操作 DOM 节点,也不能使用 window 对象的默认方法和属性。但是你可以使用大量 window 对象之下的东西,包括 WebSockets,以及 IndexedDB 等数据存储机制。查看 Web Worker 可以使用的函数和类获取详情。
workers 和主线程间的数据传递通过这样的消息机制进行——双方都使用 postMessage() 方法发送各自的消息,使用 onmessage 事件处理函数来响应消息(消息被包含在 message 事件的 data 属性中)。这个过程中数据并不是被共享而是被复制。
只要运行在同源的父页面中,worker 可以依次生成新的 worker;并且可以使用 XMLHttpRequest 进行网络 I/O,但是 XMLHttpRequest 的 responseXML 和 channel 属性总会返回 null。
如前文所述,一个专用 worker 仅能被生成它的脚本所使用。这一部分将探讨专用 worker 基础示例(运行专用 worker)中的 JavaScript 代码:将你输入的 2 个数字作乘法。输入的数字会发送给一个专用 worker,由专用 worker 作乘法后,再返回给页面进行展示。
这个例子很小,但是我们决定在保持简单的同时向你介绍基础的 worker 概念。更多的细节会在之后的文章中进行讲解。
为了更好的错误处理控制以及向下兼容,将你的 worker 运行代码包裹在以下代码中是一个很好的想法(main.js):
创建一个新的 worker 很简单。你需要做的是调用 Worker() 构造器,指定一个脚本的 URI 来执行 worker 线程(main.js):
你可以通过 postMessage() 方法和 onmessage 事件处理函数触发 worker 的方法。当你想要向一个 worker 发送消息时,你只需要这样做(main.js):
这段代码中变量 first 和 second 代表 2 个 <input> 元素;它们当中任意一个的值发生改变时,myWorker.postMessage([first.value,second.value]) 会将这 2 个值组成数组发送给 worker。你可以在消息中发送许多你想发送的东西。
在 worker 中接收到消息后,我们可以写这样一个事件处理函数代码作为响应(worker.js):
onmessage 处理函数允许我们在收到消息时运行一些代码,消息本身在 message 事件 data 属性进行使用。这里我们简单的对这 2 个数字作乘法处理并再次使用 postMessage() 方法,将结果回传给主线程。
回到主线程,我们再次使用 onmessage 以响应 worker 回传的消息:
在这里我们获取消息事件的数据,并且将它设置为显示结果段落的 textContent,所以用户可以直接看到运算的结果。
备注:在主线程中使用时,onmessage 和 postMessage() 必须挂在 worker 对象上,而在 worker 中使用时不用这样做。原因是,在 worker 内部,worker 是有效的全局作用域。
备注:当一个消息在主线程和 worker 之间传递时,它被复制或者转移了,而不是共享。请参阅worker 中数据的接收与发送:详细介绍 获取更详尽的解释。
如果你需要从主线程中立刻终止一个运行中的 worker,可以调用 worker 的 terminate 方法:
当 worker 出现运行中错误时,它的 onerror 事件处理函数会被调用。它会收到一个扩展了 ErrorEvent 接口的名为 error 的事件。
该事件不会冒泡并且可以被取消;为了防止触发默认动作,worker 可以调用错误事件的 preventDefault() 方法。
如果需要的话,worker 能够生成更多的 worker,这就是所谓的 subworker,它们必须托管在同源的父页面内。而且,subworker 解析 URI 时会相对于父 worker 的地址而不是自身页面的地址。这使得 worker 更容易记录它们之间的依赖关系。
Worker 线程能够访问一个全局函数 importScripts() 来引入脚本,该函数接受 0 个或者多个 URI 作为参数来引入资源;以下例子都是合法的:
浏览器加载并运行每一个列出的脚本。每个脚本中的全局对象都能够被 worker 使用。如果脚本无法加载,将抛出 NETWORK_ERROR 异常,接下来的代码也无法执行。而之前执行的代码(包括使用 setTimeout() 异步执行的代码)依然能够运行。importScripts() 之后的函数声明依然会被保留,因为它们始终会在其他代码之前运行。
备注:脚本的下载顺序不固定,但执行时会按照传入 importScripts() 中的文件名顺序进行。这个过程是同步完成的;直到所有脚本都下载并运行完毕,importScripts() 才会返回。
一个共享 worker 可以被多个脚本使用——即使这些脚本正在被不同的 window、iframe 或者 worker 访问。这一部分,我们会讨论共享 worker 基础示例(运行共享 worker)中的 JavaScript 代码:该示例与专用 worker 基础示例非常相像,只是有 2 个可用函数被存放在不同脚本文件中:两数相乘函数,以及求平方函数。这两个脚本使用同一个 worker 来完成实际需要的运算。
这里,我们关注一下专用 worker 和共享 worker 之间的区别。在这个示例中有 2 个 HTML 页面,每个页面所包含的 JavaScript 代码使用的是同一个 worker。
备注:如果共享 worker 可以被多个浏览上下文调用,所有这些浏览上下文必须属于同源(相同的协议,主机和端口号)。
备注:在 Firefox 中,共享 worker 不能被私有和非私有 window 对象的 document 所共享(Firefox bug 1177621)。
生成一个新的共享 worker 与生成一个专用 worker 非常相似,只是构造器的名字不同(查看 index.html 和 index2.html)——生成共享 worker 的代码如下:
本页为82搜索生成的网页快照,内容来自站内索引;演示数据的原文链接仅作示例。