Web worker的存在,为JavaScript提供了多线程的运行环境,允许主线程创建worker线程。
此文档主要介绍的是Dedicated Worker
背景
JavaScript语言设计之初采用的是单线程的模型。所有的任务都是在一个线程上通过回调来进行调度的。前面的任务没做完,后面的任务就只能等着。随着计算机算力的增强,尤其是多核CPU的出现,单线程限制了计算机算力的发挥。
作用
Web worker的存在,为JavaScript提供了多线程的运行环境,允许主线程创建worker线程,并将一些任务分配给后者。在主线程运行的同时,worker线程在后台运行,二者互不干扰。等到Worker线程完成运算后,再将运算结果返回给主线程。
优势:计算密集型或者高延迟的任务由Worker来进行,不会给主线程(负责UI与交互)造成负担(阻塞或者拖慢),增强用户体验。
缺点:Worker线程一旦创建成果,就会始终运行,不会被主线程的交互打断。这样有利于随时相应主线程的通信,但是也会浪费一定的资源,不应被过度使用。而且,一旦使用完毕,就应该尽快关闭它。
特点
同源限制
分配给Worker线程执行的脚本文件,必须与主线程的脚本同源。
DOM限制
Worker线程所在的全局对象,与主线程不同,无法读取主线程所在网页上的DOM对象。也无法使用window,document,parent这些对象。但是Worker线程可以使用Navigator和Location对象。
通信联系
Worker线程与主线程不在同一个上下文环境,它们之间不能直接通信,必须通过消息来完成。
脚本显示
Worker线程不能执行
alert()
和confirm()
方法,但可以使用XMLHTTPRequest
对象来完成Ajax
请求。文件限制
Worker线程无法读取本地文件,也就是说它无法打开本机的文件系统(file://),它加载的脚本,必须来自于网络。
用法
主线程
创建
主线程中采用Worker
构造函数来新建Worker进程,它接收一个参数,就是脚本文件(且只能加载js脚本,否则报错),即是Worker线程即将执行的任务。这个文件必须来自网络。如果加载不成功,它会静默失败。
1 | var worker = new Worker('worker.js'); |
第二个参数是可选项,用于配置,比如
name
属性可以用来自定义worker
的名字,可在worker
内使用self.name
访问到。
发送消息
然后主线程调用worker.postMessage()
方法给Worker进程发送消息。
1 | worker.postMessage('Hello world'); |
worker可以接收包括二进制在内的各种数据类型的消息内容。
接收消息
主线程可以通过worker.onmessage()
来指定监听函数,接收Worker线程发送回来的消息。
1 | worker.onmessage = function (event) { |
Worker线程发送给主线程的数据被保存在事件对象event
的data
字段上。
关闭Worker
Worker线程任务完成后,主线程就可以把它关掉。
1 | worker.terminate(); |
错误监听
1 | worker.onerror(function (err) { |
Worker线程
Worker的内部可以再新建worker
消息处理
Worker线程内部需要有一个事件监听函数,来监听message
事件。
1 | self.addEventListener('message', function (e) { |
代码中self
代表Worker线程自身,即子线程的全局对象。也可以写作this
或者省略。
也可以直接使用self.onmessage
来指定事件监听函数。
根据主线程发来的数据的不同,Worker线程可以执行不同的任务来调用不同的方法:
1 | self.addEventListener('message', function (e) { |
self.close()
用于在Worker线程内关闭自身。
加载脚本
Worker线程内部如果要加载其他脚本,有一个专门的方法importScripts。
1 | // 加载单个脚本 |
错误监听
在Worker线程内部可以监听error
事件,来捕获其内发生的错误。
同页面的Worker
通常情况下,我们会将Worker线程的代码写入一个单独的JavaScript
文件中,但是我们也可以载入和主线程在同一个网页的代码。
1 |
|
注意需要将Script
标签的type
值设置为浏览器无法识别的一个值。
再读取这段脚本,用Worker
来处理。
先将嵌入网页的脚本代码,转换成一个二进制对象,然后为这个二进制对象生成了URL,再让Worker加载这个URL。
1 | var blob = new Blob([document.querySelector('#worker').textContent]); |