JavaScript 多線程Web Worker && 在Vue中如何使用

概述

Web Workerhtml5 的新特性,JavaScript 是單線程模型,所有任務(wù)只能在一個(gè)線程上完成,一次只能做一件事。前面的任務(wù)沒做完,后面的任務(wù)只能等著, 在某些場(chǎng)景下很不方便,Web Worker 的作用,就是為 JavaScript 創(chuàng)造多線程環(huán)境,允許主線程創(chuàng)建 Worker 線程,將一些任務(wù)分配給后者運(yùn)行。在主線程運(yùn)行的同時(shí),Worker 線程在后臺(tái)運(yùn)行,兩者互不干擾。等到 Worker 線程完成計(jì)算任務(wù),再把結(jié)果返回給主線程。這樣的好處是,一些計(jì)算密集型或高延遲的任務(wù)可以交由 Worker 線程執(zhí)行,主線程能夠保持流暢,不會(huì)被阻塞或拖慢。
Worker 線程一旦新建成功,就會(huì)始終運(yùn)行,不會(huì)被主線程上的活動(dòng)(比如用戶點(diǎn)擊按鈕、提交表單)打斷。這樣有利于隨時(shí)響應(yīng)主線程的通信。但是,這也造成了 Worker比較耗費(fèi)資源,不應(yīng)該過度使用,而且一旦使用完畢,就應(yīng)該關(guān)閉

使用場(chǎng)景

任何需要始終運(yùn)行的js代碼都可以使用Worker , 比如定時(shí)器,當(dāng)頁面處于不可見狀態(tài)時(shí),定時(shí)器的執(zhí)行間隔會(huì)擴(kuò)大,這樣會(huì)造成一些程序的執(zhí)行異常,此時(shí)就可以使用webWorkers來解決

使用方法

  1. 線程創(chuàng)建
    專用線程由 Worker() 方法創(chuàng)建,可以接收兩個(gè)參數(shù),第一個(gè)參數(shù)是必填的腳本的位置,第二個(gè)參數(shù)是可選的配置對(duì)象,可以指定 type、credentials、name三個(gè)屬性
var worker = new Worker('worker.js')

共享線程使用 Shared Worker() 方法創(chuàng)建,同樣支持兩個(gè)參數(shù),用法與 Worker() 一致。

var sharedWorker = new SharedWorker('shared-worker.js')

注意: 因?yàn)?Web Worker 有同源限制,所以在本地調(diào)試的時(shí)候也需要通過啟動(dòng)本地服務(wù)器的方式訪問,使用 file:// 協(xié)議直接打開的話將會(huì)拋出異常,且Worker線程不能執(zhí)行alert()方法和confirm()方法,但可以使用XMLHttpRequest對(duì)象發(fā)出 AJAX 請(qǐng)求

  1. Worker 線程和主線程之間的通信
    Worker 線程和主線程都通過 postMessage() 方法發(fā)送消息,通過 onmessage 事件接收消息。在這個(gè)過程中數(shù)據(jù)并不是被共享的,postMessage() 一次只能發(fā)送一個(gè)對(duì)象, 如果需要發(fā)送多個(gè)參數(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 線程中,selfthis 都代表子線程的全局對(duì)象。對(duì)于監(jiān)聽 message 事件,以下的四種寫法是等同的

// 寫法 1
self.addEventListener('message', function (e) {
    // ...
})

// 寫法 2
this.addEventListener('message', function (e) {
    // ...
})

// 寫法 3
addEventListener('message', function (e) {
    // ...
})

// 寫法 4
onmessage = function (e) {
    // ...
}
  1. **關(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”報(bào)錯(cuò),這個(gè)是因?yàn)閣orker線程中不存在window對(duì)象,因此不能直接使用,要用this代替
  //   config.output.globalObject('this')
  // }
}

配置了之后 worker.js 后綴的文件就會(huì)被 loader 處理

// 在timer.worker.js
let count = 0
// 接收主線程的消息
self.addEventListener('message', (e) => {
  count = e.data
  self.postMessage(count--)
}, false)
// 用定時(shí)器發(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)
  } 
}

worker 的更多API可以查看Worker MDN

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容