持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
自JavaScript诞生以来,还没有办法在浏览器 UI 线程之外运行代码。Web Worker API 改变了这种情况,它引入了一个接口,能使代码运行且不占浏览器 UI 线程的时间。作为 HTML5 最初的一部分, Web Workers API 已经被分离出去成为独立的规范。
Web workers 给 Web 应用带来潜在的巨大性能提升,因为每个新的 Worker 都在自己的线程中运行代码。
Worker 运行环境
由于 Web Workers 没有绑定 UI 线程,这也意味着它们不能访问浏览器的许多资源。Javascript 和 UI 共享同一进程的部分原因是它们之间互相访问频繁,因此这些任务失控会导致糟糕的用户体验。Web workers 从外部线程中修改 DOM 会导致用户界面出现错误,但是每一个 Web Worker 都有自己的全局运行环境,其功能只是 JavaScript 特性的一个子集。
Worker 运行环境如下组成
- navigator 对象,包括四个属性:appName、appVersion、userAgent、platform
- location 对象
- self 对象, 指向全局 worker 对象
- importScript 对象,用来加载 Worker 所用到的外部 Javascript 文件
- 所有的 ECMAScript 对象
- XMLHttpRequest 构造器
- setTimeout和setInterval 方法
- close 方法,能够立刻停止Worker运行
由于 Web Worker 有着不同的全局运行环境,因此你无法从 JavaScript 代码中创建它。事实上,你需要创建一个完全独立的 JavaScript 文件,其中包含了需要在 Worker 中运行的代码,要创建网页人工线程,你必须传入这个 JavaScript 文件的 URL:
const worker = new Worker("code.js");
此代码一旦执行,将为这个文件创建一个新的线程和一个新的 Worker 运行环境,该文件会被异步下载,直到文件下载并执行完成之后才会启动此 Worker。
与 Worker 通信
worker 与网页代码通过事件接口进行通信。网页代码可以通过 postMessage 方法给 Worker 传递数据,它接收一个参数,即需要传递给 Worker 的数据。此外 Worker 还有一个用来接收信息的 onmessage 事件处理器:
const worker = new Worker("code.js");
woker.onmessage = function (e){
alert(event.data);
}
worker.postMessage("hello");
Worker 通过触发 message 事件来接收数据,定义 onmessage 事件处理器之后,该事件对象就具有一个 data 属性用于存放传入的数据。 Worker 可以通过它自己的 postMessage 方法把信息传给页面:
self.onmessage = function(e){
self.postMessage(e.data);
}
最终的字符串在 Worker 的 onmessage 事件处理器中构造完成。消息系统是网页和 Worker 通信的唯一途径。只有特定类型的数据可以使用 postMessage 传递。你可以传递原始值,也可以传递 Objec 和 Array 的实例,其他类型就不允许了。
加载外部文件
Worker 通过 importScripts 方法加载外部 JavaScript 文件,该方法接收一个或多个 JavaScript 文件URL 作为参数。 importScripts 的调用过程是阻塞式的,直到所有文件加载并执行完成之后,脚本才会继续运行。由于 Worker 在 UI 线程之外运行,所以这种阻塞不会影响 UI 响应
importScripts("file1.js", "file2.js");
self.onmessage = fucntion(e){
self.postmessage(e.data);
}
这段代码一行中引入了两个 JavaScript 文件,它们将在 Worker 线程上下文中用到。
实际应用
Web Worker 适用于那些处理纯数据,或者与浏览器 UI 无关的长时间运行脚本。 优势在于:
- 解析一个大字符串
- 复杂数学运算
- 大数组排序