一文读懂JavaScript多线程Web Worker

作者:异步漫步时间:2026-10-31 19:20:45浏览:428

本文详解HTML5 Web Worker标准,解析专用线程与共享线程的区别。涵盖同源、DOM及文件加载限制,演示主线程与子线程通过postMessage和onmessage进行异步通信的方法,并列出Worker实例及全局对象self的常用API,帮助开发者高效处理后台计算任务。

前言

众所周知,JavaScript运行在单线程环境中,这意味着所有任务必须按顺序在一个线程中执行,前一个任务未完成时,后续任务只能等待。为了解决这一问题,HTML5引入了Web Worker规范,允许JavaScript创建多个线程。需要注意的是,子线程完全受主线程控制,且禁止直接操作DOM,只有主线程具备DOM操作权限。因此,Web Worker最适合用于执行高耗时的数据处理或复杂计算任务,下文将深入探讨其具体用法。

正文

如何创建一个Worker?

Web Worker是HTML5规范的重要组成部分,它定义了一套API接口,使得JavaScript代码可以在主线程之外的独立线程中运行。

Web Worker规范定义了两类工作线程:专用线程(Dedicated Worker)和共享线程(Shared Worker)。专用线程仅能被创建它的单个页面使用,而共享线程则可以被多个页面共同访问和共享。

如何使用Worker?

使用Worker时需注意以下关键限制与规范:

  • 同源限制:分配给Worker线程执行的脚本文件,必须与主线程的脚本文件保持同源策略一致。
  • DOM限制:Worker线程的全局环境与主线程不同,它无法访问主线程网页的DOM对象,也不能使用document、window或parent等对象。不过,Worker线程可以访问navigator和location对象。
  • 通信机制:由于Worker线程与主线程处于不同的上下文环境,它们无法直接通信,必须通过发布-订阅模式的消息机制进行交互。
  • 脚本限制:Worker线程内部禁止执行alert()和confirm()等阻塞式方法,但允许使用XMLHttpRequest对象发起AJAX请求。
  • 文件限制:Worker线程无法读取本地文件系统(即不支持file://协议),其加载的脚本文件必须来源于网络。

如何创建 Worker 实例?

Worker构造函数接收两个参数:第一个参数是脚本文件的URL地址,这是必填项,且必须遵守同源策略,该参数仅支持加载JS脚本,否则将抛出错误;第二个参数是可选的配置对象,主要用于指定Worker的名称,以便在创建多个Worker线程时进行区分。

例如创建一个Worker:

const worker = new Worker('worker.js');

主线程与子线程如何通信?

其基本原理是在当前主线程中加载一个只读文件以创建新线程。两个线程并行存在且互不阻塞,子线程与主线程之间通过postMessage和onmessage接口实现数据交换。

例如,向Worker子线程发送消息:

// 第一种传递方式
worker.postMessage('我是主线程');

// 第二种传递方式
worker.postMessage({
  // ArrayBuffer object 
  input: buffer
}, [buffer]);

worker.postMessage()方法的参数即为主线程传递给子线程的数据,该数据支持多种数据类型,包括二进制数据。

接收子线程Work发回的消息

worker.onmessage = function (event) {
  console.log('子线程的消息:' + event.data)
}

worker.js子线程向主线程发送消息

self.postMessage('我是子线程')

接收主线程发来的消息

self.onmessage = function (event) {
  console.log('主线程的消息:' + event.data)
}

在子线程中,self代表子线程自身,即子线程的全局对象。

以下是主线程与子线程的常用API

在主线程中,worker变量表示Worker的实例:

  • worker.postMessage:主线程向worker线程发送消息,消息内容可以是任意类型的数据,包括二进制数据。
  • worker.terminate:主线程用于关闭worker线程。
  • worker.onmessage:指定当worker线程发送消息时的回调函数。也可以使用worker.addEventListener('message', cb)的方式注册监听。
  • worker.onerror:指定当worker线程发生错误时的回调函数。同样可以使用worker.addEventListener('error', cb)的方式注册监听。

在Worker线程中,全局对象为self,代表子线程自身,此时this指向self:

  • self.postMessage:worker线程向主线程发送消息,消息内容可以是任意类型的数据,包括二进制数据。
  • self.close:worker线程用于关闭自身。
  • self.onmessage:指定当主线程向worker线程发送消息时的回调函数。也可以使用self.addEventListener('message', cb)的方式注册监听。
  • self.onerror:指定当worker线程发生错误时的回调函数。也可以使用self.addEventListener('error', cb)的方式注册监听。
  • self.name:Worker的名称。该属性为只读,由构造函数指定。

载入工具函数

importScripts('work1.js', 'work2.js', ...)

importScripts是同步方法,一旦该方法返回,即可立即使用载入的脚本,无需等待回调函数。

共享线程 SharedWorker

共享线程旨在避免频繁创建和销毁线程带来的系统性能消耗,SharedWorker允许同时存在多个页面的线程连接。使用SharedWorker创建共享线程时,同样需要提供JavaScript脚本文件的URL地址或Blob对象,该脚本文件包含在线程中需要执行的代码,示例如下:

const sharedworker = new SharedWorker("sharedworker.js");

共享线程同样使用message事件来监听线程消息,但通过SharedWorker对象的port属性与线程进行通信,示例如下:

sharedworker.port.onmessage = function (event) {
  console.log(event.data)
}

也可以使用SharedWorker对象的port属性向共享线程发送消息,示例如下:

sharedworker.port.postMessage('Hello World');

到此这篇关于一文读懂JavaScript多线程Web Worker的文章就介绍到这了,更多相关JavaScript多线程Web Worker内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章