web worker产生的背景
总所周知,前端javascript是单线程工作的(前端中的线程),那如果有计算密集性、高延时的任务,前端通常会特定的调度机制通过settimeout、promise等实现,但是本质上,无论怎么样,还是在一个线程中进行工作,仍然会阻塞主Javascript线程,为了能够更好的执行,前端实现了一个web api接口—web worker。
web worker的基本概念
web worker使用限制
既然是跑在浏览器中的JavaScript代码,那么他和浏览器中的主JavaScript线程有哪些不一样呢?
web worker操作限制:
- 不能操作DOM,不能使用Document、Window、Parent这些对象。但是,可以使用navigator对象和location对象。
- 同源限制,worker脚本和主线程必须同源
- 不能alert、不能confirm,但是可以使用ajax(通常可以用来轮询后台数据)
- 主线程和worker线程,不能直接通信,必须通过消息传递
web worker分类和使用
web worker分类两类:
- 专用worker(Dedicated Worker)
默认创建的就是专用worker,专用worker是只能和构造的进行通信,worker中的全局作用域为DedicatedWorkerGlobalScope - 共享worker(Shared Worker)
创建共享worker,共享worker可以为不同的浏览器上下文提供服务,可以是不同的窗口、iframe或者是worker,各个创建者共享worker的实例,全局作用域为SharedWorkerGlobalScope - Service Worker
service worker是用来充当浏览器和网络之间的代理,提供更好的离线体验
worker特点:
- worker中可以通过importScripts**,导入其他的script片段,也可以通过blob创建URL引用同一个页面的script片段
专用worker
主线程:
let s = new Worker('worker.js');
s.postMessage({
data: 'dedicated worker'
});
//监听消息
s.onmessage = function (event) {
console.log(2, event.data);
// 记得关闭哦,不然会消耗资源
s.terminate();
}
// 监听错误事件
s.onerror = function (event) {
console.log('error', event);
}
worker线程
onmessage = function(e) {
console.log('e',e)
postMessage('workerResult');
// 记得关闭
self.close();
}
还有另一种方式:
// worker中self和this都指向DedicatedWorkerGlobalScope
this.addEventListener('message', (e) => {
console.log(e.data);
},false);
共享worker
共享worker需要借助port来启动
主线程
let share = new SharedWorker('worker.js');
share.port.start();
share.port.postMessage({
data: '123'
});
share.port.onmessage = function (event) {
console.log(1, event.data);
}
worker线程
onconnect = function(e) {
var port = e.ports[0];
port.onmessage = function(e) {
port.postMessage('workerResult');
}
}
web worker的原理
Message
- message,不是引用,而是先将数据序列化,再将数据反序列化,通过传值的方式,但是这样会存在一个性能问题,所以worker允许直接传递二进制数据,但是传递之后,原线程将不能再使用该数据。
Meaage队列
- 在你new worker的时候,是异步创建的,在浏览器中存储一个消息队列,当worker创建成功之后,再将消息push进worker线程中去
web worker的接口继承关系
详情请看MDN文档WorkerGlobalScope
// 有点麻烦,反正就是各个接口之间耦合,从不同的接口中继承了不同的方法,自己也实现了不同的方法
DedicatedWorkerGlobalScope --->
SharedWorkerGlobalScope ---> WorkerGlobalScope --> EventTarget
ServiceWorkerGlobalScope --->
在webpack中使用web worker
{
// 匹配 *.worker.js
test: /\.worker\.js$/,
use: [{
loader: 'worker-loader',
options: {
name: '[name].js',
inline: true,
fallback: false
// publicPath: '/scripts/workers/'
}
},'babel-loader']
}