web worker
众所周知,JavaScript
是单线程,无法进行并行操作;因而 H5 中增加了 Web Worker
,提供多线程解决方案;Web Worker
允许一段 JavaScript
程序运行在主线程之外的另外一个线程中
主线程与 worker
之间,以及 worker
与 worker
之间通过 postMessage()
、message
来通信
web worker
分两种类型:一种是专用线程(dedicated web worker
),另一种是共享线程(shared web worker
);前者被创建它的页面访问,后者在多个页面间共享
构建
1 | const worker = new worker(url, options); // 专用线程 |
url
必须遵循同源策略可以通过
options
指定worker
名称
通信
1 | // main |
主线程和 worker
线程之间通过通过互相调用 sendMessage
、onMessage
来通信的 MessagePort 对象进行通信;专用线程使用隐式的 MessagePort
实例,专用线程被创建时,MessagePort 的端口消息队列便被主动启用;这与共享线程的 start()
效果一样
MessagePort
通信方式是深拷贝,即是传值而不是地址,子线程对通信内容的修改,不会影响到主线程;浏览器内部
线程之间传输的数据类型可以是字符串、对象,也可以是二进制数据,如 File
、Blob
、ArrayBuffer
等
线程之间传输数据的方式有两种:一种是采用 MessagePort 方式进行通信(深拷贝),浏览器内部通过 structured clone algorithm ,将发送端的数据进行序列化并拷贝,接收端收到的数据进行反序列化,这样两端的数据在发生更改时不会相互影响;另一种采用 Transferable Objects 方式进行通信(转移),这种方式主要用于二进制数据的传递,它对数据不做任何拷贝而是直接将数据值的引用转移给数据接收端,而数据发送端不会再持有该数据的引用,这样可以防止出现多个线程同时修改数据
使用 JSON.stringify
序列化需要传输的数据,根据 Nolan Lawson 的测试结果,证明传输 stringify
后的数据比传输原始数据更优
调试
在 Chrome
中打开 chrome://inspect/#workers
异常处理
-
event
对象中包含发生异常的文件(filename
)、行号(lineno
)以及相应的错误信息(message
)1
2
3worker.addEventListener('error', (event) = {
console.info(`${event.filename}-${event.lineno}-${event.message}`);
}); -
1
worker.onmessageerror = (event) = { console.dir(event); };
结束
有三种方式结束 worker:
- 主线程调用
worker.terminate()
worker
内部调用self.close()
- 关闭页面(捂脸)
sub worker
worker
中可以创建子 worker
,但有两点需要留意:
- 子
worker
与父worker
必须同源 - 子
worker
的url
是相对 父worker
,而不是主线程
inline worker
需要及时释放
Blob URL
(window.URL.revokeObjectURL(blobURL)
)
Chrome
中可以在chrome://blob-internals/
中查看所有的 Blob URLs
加载外部脚本
Worker
线程能够访问一个全局函数 importScripts()
来引入外部脚本,该函数可以接受多个 url
,url
必须保证同源
;如果加载失败,则后续代码无法执行。
脚本的执行顺序依照传入函数的顺序,但下载顺序不固定。这个过程是同步的,所有脚本下载并执行完,函数才会返回。
1 | importScripts(); |
worker 执行流程
局限
Worker
不同于 window
,它运行在另一个全局作用域(DedicatedWorkerGlobalScope
和 SharedWorkerGlobalScope
)中,有些 window
中的属性和方法无法在 worker
中访问,具体可以查看这篇文章;
不允许访问的对象包括:DOM
、document
、window
、parent
、LocalStorage
允许访问的对象包括:navigator
、location(只读)
、XMLHttpRequest
、setTimeout / setInterval
、Application Cache
扩展
worker
执行环境中self
和this
都指向worker
的全局作用域,以下三种写法效果一样self
也提供一系列接口,包括:self.JSON
、self.Math
、self.console
应用
数据运算
-
Ng
将繁重的计算(如dirty checking
)放到worker
中,提升渲染性能 -
React
将dom diff
移到worker
中计算,再将计算结果发给主线程 -
Redux
中reducer
计算状态的部分移到Worker
中
-
- 大量数据的检索、分析
- 图像处理
- 音频 / 视频解码