多线程的JavaScript: Web Worker
Web Worker是 HTML5推出的标准
Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application.
优点
允许 JavaScript 脚本创建多个线程,从而充分利用 CPU 的多核计算能力,不会阻塞主线程 (一般指 UI 渲染线程) 的运行, 兼容性良好,基本覆盖了所有主流浏览器
局限
Web Worker本质上没有突破JS的单线程的性质,Web Worker脚步不能直接操作DOM节点, 不能使用绝大多数的BOM API。 上下文环境是DedicatedWorkerGlobalScope 而不是Window。 运行Worker的实际上是一个沙箱,跑的是与主线程完全独立的JavaScript文件。
使用场景
作为主线程的附属,完成高 CPU 计算型的数据处理,再通过线程间通信将执行结果传回给主线程。在整个过程中,主线程仍然能正常地相应用户操作,从而很好地避免页面的卡顿现象。
具体场景:
- 预加载数据:可以使用Worker提前加载数据,实现秒开
- 拼写检查
- 加密: 有时候加密会非常耗时。
- 渐进式网络应用PWA: 例如:通过与IndexDB的整合实现离线访问
如何使用
新建
const worker = new Worker("./worker.js");
通信
// main.js
const worker = new Worker("./worker.js");
// 主线程发送消息
worker.postMessage({ data: '黄某还是挺不错的' });
// 主线程接收消息
worker.onmessage = (e) => {
const { data } = e;
if (!data) return;
console.log(data);
}
// worker.js
// worker线程接收消息
self.addEventListener('message', (e) => {
const { data } = e;
if (!data) return;
// worker线程发送消息
self.postMessage({data: 'worker received data'})
});
注: Worker 中,this.xx, self.xx 与直接使用 xx,其作用域都指向 worker 的全局变量 DedicatedWorkerGlobalScope ,可以互换
销毁
两种方式
// 第一种:主线程通知销毁
// main.js
worker.terminate();
// worker.js
self.close();
Worker加载脚本
importScripts('script1.js');
// 或者可以加载多个
importScripts('script1.js', 'script2.js');
错误处理
主线程可以监听Worker是否发生错误
worker.onerror(function (event) {
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));
});
// 内部也可以监听error事件
worker.addEventListener('error', function (event) {
// ...
});
参考:
- 给 JavaScript 插上多线程的翅膀 —— Web Worker 的 Promise 化实践:http://www.alloyteam.com/2020/07/14645/
- 阮一峰网络日志Web Worker使用教程 http://www.ruanyifeng.com/blog/2018/07/web-worker.html
- 微信小程序多线程Workerhttps://developers.weixin.qq.com/miniprogram/dev/framework/workers.html
- uniapp Worker: https://uniapp.dcloud.io/api/worker
dev/framework/workers.html)
- uniapp Worker: https://uniapp.dcloud.io/api/worker