# Web Workers

因为 Javascript 从设计之初就是单线程的,所以它没有原生支持多线程操作。它没有办法在浏览器 UI 线程之外运行代码。Web Workers API 改变了这种状况,它引入了一个接口,能够使代码运行且不占用浏览器 UI 线程的时间。作为 HTML5 最初的一部分,Web Workers API 已经被分离出去称为独立的规范。

Web Workers 给 Web 应用带来的潜在的巨大性能提升,因为每个 Worker 都在自己的线程中运行代码。这意味着 Worker 运行代码不仅不会影响浏览器 UI,也不会影响其它 Worker 中运行的代码。

# Worker 运行环境

由于 Web Workers 没有绑定 UI 线程,这也意味着它们不能访问浏览器的许多资源。Javascript 和 UI 共享同一线程的部分原因是它们之间互相访问频繁,因此这些任务失控回导致糟糕的用户体验。Web Workers 从外部线程中修改 DOM 会导致用户界面出现错误。但是每个 Web Worker 都有自己的全局运行环境,其功能只是 javascript 特性的一个子集。Web Worker 运行环境如下部分组成:

  • navigator 对象,只包含四个属性:appName、appVersion、userAgent 和 platform
  • location 对象,与 window.location 相同只是所有属性都是只读的
  • self 对象,指向全局 worker 对象
  • importScript 方法,用来加载 Worker 所用到的外部 Javascript 文件
  • 所有 ECMAScript 对象,如 Object、Array、Date、Math 等
  • XMLHttpRequest 构造器
  • setTimeout 和 setInterval 方法
  • close 方法,它能够立即停止 Worker 运行

Web Worker 有着不同的全局运行环境,因此你无法从 Javascript 的代码中创建它。使用它需要一个完全独立的 js 文件,里面包含 Worker 中运行代码。

var worker = new Worker("test.js");

这个代码一但执行,将为这个文件创建一个新的线程和一个新的 Worker 运行环境。该文件会被异步下载,直到文件被下载并执行完成后才会启动此 Worker

# 与 Worker 通信

Worker 与网页代码通过事件接口通信。网页代码可以使用 postMessage() 方法给 Worker 传递数据,它接受一个参数。此外 Worker 中有用于接收信息的 onmessage 事件处理器。

var worker = new Worker("test.js");
worker.onmessage = function(event){
  console.log(event.data); // hello,world
};
worker.postMessage("Asuhe");

Worker 内通过触发 message 事件来接收数据。Worker 可以通过自己的 postMessage() 方法来把数据传递回页面。

// test.js
self.onmessage = function(event){
  console.log(event.data); // Asuhe
  self.postMessage("hello,world");
}

这种方式是它们之间通信的唯一方式。

允许传递基本类型的数据和对象。其它类型的数据不允许被传递。

# Worker 加载外部文件

Worker 通过 importScript() 方法加载外部 js 文件,该方法可以接受一个或多个 js 文件的 url 作为参数。它的调用过程是阻塞式的,直到所有文件成功加载并执行后才会继续运行后续其它代码。