什么是 Web Worker?
我们一直强调JavaScript是单线程的,但是web worker的出现使得JavaScript可以在多线程上跑,只是web worker本身适合用于一些复杂的、耗费cpu的运算,不能操作window、document、parent对象,所以说本质上的JavaScript还是单线程的。
web worker就是运行在后台的JavaScript,独立于其他脚本,不会影响页面的性能。您还可以做任意想做的事情,不会影响点击等操作。
Web Worker 有三种类型:
- Dedicated Worker(专用 Worker):由主线程实例化且只能与它通信,不能访问别的环境。
- Shared Worker(共享 Worker):所有 Shared Worker 实例共享一个全局环境,多个页面可以用 Shared Worker 互相通信,可以处理多个连接。
- Service worker(服务 Worker):具有 Shared Worker 的特点、通过事件驱动,可以随时关闭再重启、不需要任何页面也能工作,只支持 https 和 localhost。多用于离线场景
平常使用最多,最常见的就是 Dedicated Worker,并且 Dedicated Worker 兼容性较好
为什么需要web worker?
对于耗时而不操作DOM的JavaScript,我们就可以使用web worker,增强性能。
web worker有什么要注意的地方?
- 不是所有的浏览器都支持,使用前要检查浏览器是否支持。
- web worker运行于外部文件中,所以他们无法访问下面的JavaScript对象。
- 理解好 worker,worker在计算机领域通常被翻译为线程或者是进程。而这里的worker意义也是如此。 我们需要将之正确对待。
web worke基本用法
var worker = new Worker('work.js');
<p>计数:<span id="result"></span></p>
<button onclick="start()">web worker开始工作</button>
<button onclick="stop()">web worker结束工作</button>
<script>
var w;
function start() {
if (typeof Worker != 'undefined') {
w = new Worker('worker.js'); // 创建 Web Worker 对象
// 向 web worker 添加一个 "onmessage" 事件监听器:
w.onmessage = function (event) {
document.getElementById('result').innerHTML = event.data;
}
} else {
document.getElementById('result').innerHTML = '您的浏览器不支持web worker';
}
}
function stop() {
w.terminate(); // 终止 Web Worker
w = undefined;
}
SharedWorker使用
SharedWorker 是一种特殊的 WebWorker,可有支持多个浏览器上下文的通信功能,例如多个窗口、iframe。
但是与普通 Worker 不同的是:
1 同一个js url 只会创建一个 sharedWorker,其他页面再使用同样的url创建sharedWorker,会复用已创建的 worker,这个worker由那几个页面共享。
2 sharedWorker通过port来发送和接收消息
接下来,我们看一下具体是 worker 和页面之间是如何发送和接收消息的。
方法
- start:开启连接
- connect:连接
- postMessage:发送数据
- onmessage:接收数据
<body>
<input type="text" id="input">
<button id="submit">提交</button>
<p id="news"></p>
</body>
<script>
let work = new SharedWorker('work.js');
let port = work.port;
//开启
port.start();
//通知所有人
port.postMessage({ type: "start" });
//点击触发事件
submit.onclick = function (e) {
port.postMessage({
type: "msg",
value: input.value
});
input.value = "";
}
//接收数据
port.onmessage = function (e) {
console.log(e.data)
if (Array.isArray(e.data)) {
let html = "";
e.data.forEach(msg => {
html += `<p>${msg}</p>`;
});
news.innerHTML = html;
} else {
news.innerHTML = e.data;
}
}
</script>