概述
Web Worker
是 html5
的新特性竭宰,JavaScript
是單線程模型莺禁,所有任務(wù)只能在一個線程上完成松蒜,一次只能做一件事丢氢。前面的任務(wù)沒做完,后面的任務(wù)只能等著裕寨, 在某些場景下很不方便浩蓉,Web Worker
的作用派继,就是為 JavaScript
創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker
線程捻艳,將一些任務(wù)分配給后者運行驾窟。在主線程運行的同時,Worker
線程在后臺運行认轨,兩者互不干擾绅络。等到 Worker
線程完成計算任務(wù),再把結(jié)果返回給主線程嘁字。這樣的好處是恩急,一些計算密集型或高延遲的任務(wù)可以交由 Worker
線程執(zhí)行,主線程能夠保持流暢纪蜒,不會被阻塞或拖慢衷恭。
Worker
線程一旦新建成功,就會始終運行纯续,不會被主線程上的活動(比如用戶點擊按鈕匾荆、提交表單)打斷。這樣有利于隨時響應(yīng)主線程的通信杆烁。但是牙丽,這也造成了 Worker
比較耗費資源,不應(yīng)該過度使用兔魂,而且一旦使用完畢烤芦,就應(yīng)該關(guān)閉
使用場景
任何需要始終運行的js
代碼都可以使用Worker
, 比如定時器析校,當(dāng)頁面處于不可見狀態(tài)時构罗,定時器的執(zhí)行間隔會擴大,這樣會造成一些程序的執(zhí)行異常智玻,此時就可以使用webWorkers
來解決
使用方法
-
線程創(chuàng)建
專用線程由Worker()
方法創(chuàng)建遂唧,可以接收兩個參數(shù),第一個參數(shù)是必填的腳本的位置吊奢,第二個參數(shù)是可選的配置對象盖彭,可以指定type
、credentials
页滚、name
三個屬性
var worker = new Worker('worker.js')
共享線程使用 Shared Worker() 方法創(chuàng)建召边,同樣支持兩個參數(shù),用法與 Worker() 一致裹驰。
var sharedWorker = new SharedWorker('shared-worker.js')
注意: 因為 Web Worker 有同源限制隧熙,所以在本地調(diào)試的時候也需要通過啟動本地服務(wù)器的方式訪問,使用 file:// 協(xié)議直接打開的話將會拋出異常幻林,且Worker
線程不能執(zhí)行alert()
方法和confirm()
方法贞盯,但可以使用XMLHttpRequest
對象發(fā)出 AJAX 請求
-
Worker 線程和主線程之間的通信
Worker
線程和主線程都通過postMessage()
方法發(fā)送消息音念,通過onmessage
事件接收消息。在這個過程中數(shù)據(jù)并不是被共享的躏敢,postMessage()
一次只能發(fā)送一個對象症昏, 如果需要發(fā)送多個參數(shù)可以將參數(shù)包裝為數(shù)組或?qū)ο笤龠M(jìn)行傳遞
// 主線程
var worker = new Worker('worker.js')
worker.postMessage([10, 24])
worker.onmessage = function(e) {
console.log(e.data)
}
// Worker 線程
onmessage = function (e) {
if (e.data.length > 1) {
postMessage(e.data[1] - e.data[0])
}
}
在 Worker
線程中,self
和 this
都代表子線程的全局對象父丰。對于監(jiān)聽 message 事件,以下的四種寫法是等同的
// 寫法 1
self.addEventListener('message', function (e) {
// ...
})
// 寫法 2
this.addEventListener('message', function (e) {
// ...
})
// 寫法 3
addEventListener('message', function (e) {
// ...
})
// 寫法 4
onmessage = function (e) {
// ...
}
- **關(guān)閉 Worker **
// 主線程
worker.terminate()
// Dedicated Worker 線程中
self.close()
// Shared Worker 線程中
self.port.close()
在vue中使用Worker
首先要安裝laoder
npm i -D worker-loader
在vue.config.js
中配置以下
module.exports = {
// ...
chainWebpack(config) {
config.module
.rule('worker')
.test(/\.worker\.js$/)
.use('worker-loader')
.loader('worker-loader')
.end();
config.module.rule('js').exclude.add(/\.worker\.js$/)
},
parallel: false,
// chainWebpack: config => {
// // 解決:“window is undefined”報錯掘宪,這個是因為worker線程中不存在window對象蛾扇,因此不能直接使用,要用this代替
// config.output.globalObject('this')
// }
}
配置了之后 worker.js
后綴的文件就會被 loader
處理
// 在timer.worker.js
let count = 0
// 接收主線程的消息
self.addEventListener('message', (e) => {
count = e.data
self.postMessage(count--)
}, false)
// 用定時器發(fā)消息
setInterval(() => {
// postMessage 用于數(shù)據(jù)交互
self.postMessage(count)
count--
}, 1000)
// 在vue中
import Worker from './prompt.worker.js'
mounted() {
this.worker = new Worker()
this.worker.postMessage('給線程發(fā)消息')
this.worker.onmessage = (event) => {
console.log('接收到的消息為:' + event.data)
}
}