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中
-
- 大量数据的检索、分析
- 图像处理
- 音频 / 视频解码
