js是单线程语言,无法开启多个线程同时执行。HTML5中,浏览器提供了一种新特性web worker,让我们可以在页面主运行的 JavaScript 线程中加载运行另外单独的一个或者多个 JavaScript 线程。这样,在主线程处理页面渲染和交互的同时,web worker可处理一些复杂计算,当有结果后通知给主线程。
专用/共享
专用线程Dedicated Worker:一个worker线程对应一个js主线程。浏览器支持率很高。
共享线程 Shared Worker:一个worker线程可以被多个同源js主线程使用。需要指定port,显示打开后才能使用。浏览器支持率较低,较少使用。
// 主线程
const sharedWorker = new SharedWorker('./sharedWorker.js');
sharedWorker.port.onmessage = function(e) {
// 业务逻辑
}
sharedWorker.port.start() // 需要显式打开
sharedWorker.port.postMessage([10, 24])
// Worker 线程
onconnect = function (e) {
let port = e.ports[0]
port.onmessage = function (e) {
if (e.data.length > 1) {
port.postMessage(e.data[1] - e.data[0])
}
}
}
由于共享线程sharedWorker目前支持情况较差,下文主要介绍专用线程worker。
使用
// main.js
// 实例化一个worker
const worker = new Worker('../src/worker.js');
// 监听message事件
worker.onmessage = e => {
console.log(e.data); // "Polo"
}
// 错误处理
// 将普通错误冒泡上来
worker.onerror = e => {
console.log(e); // a is undefined
}
// onmessageerror 监听发送的数据不能被反序列化错误
// 发送数据事件
worker.pushMessage("Marco");
// 立即终止worker线程中全部操作
worker.terminate();
// worker.js
// 监听message事件
onmessage = e => {
console.log(e.data); // "Marco"
console.log(a) // 抛出错误
// 发送数据事件
pushMessage("Polo");
}
// 关闭当前worker线程
close();
// 引用外部脚本
importScripts(urlA, urlB);
worker和主线程中的数据传递,是通过复制数据,将数据的副本用于传输,(序列化/反序列化,浏览器中主要通过JSON编码/解码),所以是两份相互独立的数据。
可以获取到部分浏览器提供的 API :
setTimeout(), clearTimeout(), setInterval(), clearInterval()
:有了设计个函数,就可以在 Worker 线程中执行定时操作了;
XMLHttpRequest
对象:意味着我们可以在 Worker 线程中执行 ajax 请求;
navigator
对象:可以获取到 ppName,appVersion,platform,userAgent 等信息;
location
对象(只读):可以获取到有关当前 URL 的信息;
局限性
- 不能访问DOM
- 没有window全局对象
- 同源限制:js主线程和worker必须同源
本地调试,也需要起服务,可以用browser-sync。
使用场景
- 懒加载
- 文本分析
- 流媒体数据处理
- canvas 图形绘制
- 图像处理
- ...