Web Worker规范定义了在网络应用中生成背景脚本的API。
我们可以通过Web Worker执行一些操作,例如触发长时间运行的脚本以处理计算密集型任务,同时却不会阻碍 UI或其他脚本处理用户互动。
值得注意的是,规范中提到了两种Worker:专用Worker以及共享Worker。本文只讲专用Worker,下文称之为“Web Worker”或“Worker”。
入门
Web Worker
是在独立线程中运行的,因此,它们执行的代码需要保存在一个单独的文件中,我们可以这样创建一个Worker:
1 | var worker = new Worker('/assets/js/tests/simple-web-worker.js'); |
如果指定的异步下载文件存在,浏览器就会生成新的Worker线程。在完全下载并执行文件之前,系统不会生成Worker。如果指定的文件不存在,Worker就不会创建成功。
全局作用域
Worker拥有一个独立于JavaScript执行环境的全局作用域,它不能访问DOM以及大部分BOM,它只能使用JavaScript的一部分功能:
XMLHttpRequest
self
,Worker作用域内的全局对象,等同于Worker中的this
navigator
,这是个被阉割的对象,在Worker中,它仅包含了部分属性location
,等同于window.location
,但是所有属性都是只读的。setTimeout
和setInterval
- 一个
importScripts
方法,用于向Worker注入外部脚本文件。 - 所有ECMAScript规范中定义的构造器。
既然是一个独立的执行环境,那Worker中的所有全局变量都应该是self
的属性,比如:
1 | onmessage = function(e) { |
这样写虽然没问题,但是不好理解,所以建议这么写:
1 | self.onmessage = function(e) { |
其实,更优雅的方式应该是这样:
1 | self.addEventListener('message', function(e) { |
消息传递
Worker不能直接影响页面,它需要通过一个消息系统来传递消息。
Worker可以通过postMessage
方法来传递消息,例如:
主页面:
1 | <button onclick="sayHI()">打招呼</button> |
在Worker文件中:
1 | self.addEventListener('message', function(e) { |
示例:运行此Worker!
后记
在使用Worker时,可能需要关闭Worker,通常有以下两种办法:
- 在主线程脚本中调用
worker.terminate()
- 在Worker内部中调用
self.close()
Worker一旦关闭后,就不再可用。