最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文帶你掌握J(rèn)avaScript中worker的具體使用

 更新時(shí)間:2026年01月04日 09:15:10   作者:南風(fēng)晚來(lái)晚相識(shí)  
Worker?是在Web應(yīng)用程序中實(shí)現(xiàn)多線程的機(jī)制,它可以在一個(gè)單獨(dú)的線程中運(yùn)行腳本,獨(dú)立于主線程,下面小編就和大家詳細(xì)介紹一下JavaScript中worker的具體使用吧

什么是 JavaScript Worker

Worker 是在Web應(yīng)用程序中實(shí)現(xiàn)多線程的機(jī)制。它可以在一個(gè)單獨(dú)的線程中運(yùn)行腳本,獨(dú)立于主線程。

這樣,我們可以將一些耗時(shí)的計(jì)算任務(wù)交給Worker線程處理。以保證主線程的不會(huì)被阻塞。

為什么需要Worker

由于JavaScript是單線程的,所有任務(wù)在一個(gè)線程上執(zhí)行。如果遇到一個(gè)耗時(shí)的任務(wù)(比如大規(guī)模數(shù)據(jù)計(jì)算、圖像處理、復(fù)雜算法)。它會(huì)阻塞主線程導(dǎo)致頁(yè)面無(wú)法響應(yīng),用戶體驗(yàn)變差。

Worker的出現(xiàn)就是為了解決這個(gè)問(wèn)題,將耗時(shí)的計(jì)算任務(wù)放到后臺(tái)線程去執(zhí)行。

vue2中如何使用 worker

在vue/cli腳手架中,我們無(wú)法直接使用worker。

因?yàn)椋?/p>

1,無(wú)法將 Worker 腳本打包為獨(dú)立的可加載文件。

2,打包后會(huì)導(dǎo)致依賴丟失或路徑錯(cuò)誤。

npm install worker-loader -D

或者

yarn add worker-loader -D

vue.config.js 配置如下

module.exports = {
  chainWebpack:config=>{
    // 下面是worker的配置
    .rule('worker')
    .test(/\.worker\.js$/)
    .use('worker-loader')
    .loader('worker-loader')
    .end();

    // 解決:worker 熱更新問(wèn)題
    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')
  }
}

postMessage 子線程給主線發(fā)送消息

self.postMessage子線程向主線程發(fā)送消息。在 Web Worker 中,self 指向當(dāng)前創(chuàng)建的這個(gè) worker 線程,self 是一個(gè)全局對(duì)象。

self.postMessage()將數(shù)據(jù)從 worker 線程發(fā)送到創(chuàng)建它的主線程。

主線程通知子線程(worker)開始工作

// 創(chuàng)建 worker
this.webWorker = new Worker('./web.worker.js')
// 通知 Worker 子線程可以進(jìn)行響應(yīng)的工作。
// 主線程調(diào)用worker.postMessage()方法,向 Worker 發(fā)消息
this.webWorker.postMessage({ action: 'startFetch' });

worker 發(fā)送網(wǎng)絡(luò)請(qǐng)求

src\views\element.vue 文件

<template>
  <div class="page">
    <h1>使用worker來(lái)發(fā)發(fā)送網(wǎng)絡(luò)請(qǐng)求</h1>
    <el-button @click="sendFetchHandler">開始發(fā)送網(wǎng)絡(luò)請(qǐng)求</el-button>

    <ul>
      <li v-for="(item,index) in apiBackData" :key="index">{{ item.title }}</li>
    </ul>
  </div>
</template>

<script>
// 導(dǎo)入 worker 文件, 必須使用 這樣的方式引入
import WorkerA from 'worker-loader!./web.worker.js'
export default {
  data() {
    return {
      apiBackData: []
    }
  },
  methods: {
    sendFetchHandler(){
      // 主線程調(diào)用worker.postMessage()方法,向 Worker線程 發(fā)消息,開始進(jìn)行網(wǎng)絡(luò)請(qǐng)求
      this.webWorker1.postMessage({ action: 'startFetch' });
    }
  },
  created() {
    // 創(chuàng)建 worker 實(shí)例,名稱必須和導(dǎo)入時(shí)的保持一致
    this.webWorker1 = new WorkerA('./web.worker.js')
    // 先添加事件監(jiān)聽器
    this.webWorker1.addEventListener('message', (e) => {
      // e.data 是接收到的數(shù)據(jù)
      console.log('收到來(lái)自 Worker 的消息:', e.data)
      // 處理 Worker 返回的數(shù)據(jù)
      if (e.data.type === 'fetchSuccess') {
        this.apiBackData = e.data.data.data || []
        console.log('獲取的數(shù)據(jù):',  this.apiBackData );
      } else if (e.data.type === 'fetchError') {
        console.log('獲取數(shù)據(jù)失敗:', e.data.error);
      }
    })

    this.webWorker1.addEventListener('error', (error) => {
      console.error('Worker發(fā)生錯(cuò)誤:', error)
    })
  }
}
</script>
// 引入網(wǎng)絡(luò)請(qǐng)求中的方法
import {getList} from '@/request/api.js'

self.onmessage = function(e) {
  console.log("worker:", e)
  if(e.data && e.data.action==='startFetch'){
    //  e.data是主線程發(fā)送過(guò)來(lái)的數(shù)據(jù)
    getList().then(res=>{
      console.log(1111,res)
      // 假設(shè) 是一個(gè)數(shù)組就是請(qǐng)求成功
      if(Array.isArray(res)){
        //將數(shù)據(jù)從 worker 線程發(fā)送到創(chuàng)建它的主線程
        self.postMessage({ 
          type: 'fetchSuccess',
          data:{
            data:res,
            message: '獲取成功'
          }
        });
      }else{
        // 將數(shù)據(jù)從 worker 線程發(fā)送到創(chuàng)建它的主線程
        self.postMessage({ type: 'fetchError', error: '請(qǐng)求失敗' });
      }
    })
  }
};

worker導(dǎo)出表格案例

<template>
  <div class="page">
    <input type="text">
    

    <el-button @click="exportExcelHandler">導(dǎo)出excel</el-button>
  </div>
</template>

<script>
import {writeFile, utils} from 'xlsx'
export default {
  data() {
    return {
      
    }
  },
  methods: {
    exportExcelHandler(){
      let arr = []
      // 50w行的數(shù)據(jù)
      for(let i= 0; i<500000;i++){
        arr.push({
          name: '張' + i,
          age: 18,
          sex: '男',
          id: '2025_12_12'+ i,
          address:'XX區(qū)YYY大道' + i + '號(hào)'
        })
      }
      // 將對(duì)象數(shù)組 arr 轉(zhuǎn)換為 Excel 工作表(sheet)
      const sheet  = utils.json_to_sheet(arr)
      // 創(chuàng)建一個(gè)新的空工作簿對(duì)象。
      // 工作簿是 Excel 文件的容器,可以包含多個(gè)工作表
      const workbook = utils.book_new()
      // 將之前創(chuàng)建的工作表 sheet 添加到工作簿 workbook 中
      utils.book_append_sheet(workbook, sheet, 'sheet1')
      console.log('workbook', workbook)
      // 將整個(gè)工作簿 workbook 寫入文件并觸發(fā)瀏覽器下載
      writeFile(workbook, 'test.xlsx')
      // 主線程調(diào)用worker.postMessage()方法,向 Worker線程 發(fā)消息,開始進(jìn)行網(wǎng)絡(luò)請(qǐng)求
      // this.webWorker1.postMessage({ action: 'startFetch', data: this.vueData });
    }
  }
}
</script>

worker解決添加數(shù)據(jù)耗時(shí)問(wèn)題

下載xlsx模塊。

npm install --save xlsx

使用worker的文件(下載的主頁(yè)面)

<template>
  <div class="page">
    <input type="text">
    

    <el-button @click="exportExcelHandler">導(dǎo)出excel</el-button>

  </div>
</template>

<script>
// 導(dǎo)入 worker 文件, 必須使用 這樣的方式引入
import WorkerA from 'worker-loader!./web.worker.js'
import {writeFile} from 'xlsx'
export default {
  data() {
    return {
      
    }
  },
  methods: {
    exportExcelHandler(){
      // 主線程調(diào)用worker.postMessage()方法,向 Worker線程 發(fā)消息,開始進(jìn)行構(gòu)造數(shù)據(jù)
      this.webWorker1.postMessage({ action: 'startCreateExcelData'});
    }
  },
  created() {
    // 創(chuàng)建 worker 實(shí)例,名稱必須和導(dǎo)入時(shí)的保持一致
    this.webWorker1 = new WorkerA('./web.worker.js')
    // 先添加事件監(jiān)聽器
    this.webWorker1.addEventListener('message', (e) => {
      console.log('收到來(lái)自 Worker 的消息:', e.data)
      // 處理 Worker 返回的數(shù)據(jù)
      if (e.data.type === 'createExcelSuccess') {
        // 返回表的數(shù)據(jù)
        const workbook = e.data.data.data
        // 將整個(gè)工作簿 workbook 寫入文件并觸發(fā)瀏覽器下載。
        // 最后異步仍然會(huì)卡頓,因?yàn)閿?shù)據(jù)量太大了.但是卡頓的時(shí)間會(huì)比之前好一些
        writeFile(workbook, '通過(guò)worker導(dǎo)處excel.xlsx')
      } else  {
        console.log('獲取數(shù)據(jù)失敗:', e.data.error);
      }
    })

    this.webWorker1.addEventListener('error', (error) => {
      console.error('Worker發(fā)生錯(cuò)誤:', error)
    })
  }
}
</script>

worker文件(src\views\web.worker.js )

// 引入 xlsx
import {utils} from 'xlsx'
self.onmessage = function(e) {
  console.log("worker:", e)
  if(e.data && e.data.action==='startCreateExcelData'){
    //  e.data是主線程發(fā)送過(guò)來(lái)的數(shù)據(jù)
    let arr = []
    // 50w行的數(shù)據(jù)
    for(let i= 0; i<500000;i++){
      arr.push({
        name: '張' + i,
        age: 18,
        sex: '男',
        id: '2025_12_12'+ i,
        address:'XX區(qū)YYY大道' + i + '號(hào)'
      })
    }
    // 將對(duì)象數(shù)組 arr 轉(zhuǎn)換為 Excel 工作表(sheet)
    const sheet  = utils.json_to_sheet(arr)
    // 創(chuàng)建一個(gè)新的空工作簿(book)對(duì)象。工作簿是 Excel 文件的容器,可以包含多個(gè)工作表(sheet)
    const workbook = utils.book_new()
    // 將之前創(chuàng)建的工作表 (sheet) 添加到工作簿(workbook)中
    utils.book_append_sheet(workbook, sheet, 'sheet1')
    self.postMessage({ 
      type: 'createExcelSuccess',
      data:{
        data:workbook,
        message: '獲取成功'
      }
    });
  }
};

關(guān)閉 Web Worker

在主線程和在Worker線程的關(guān)閉方式是不一樣的。如果在主線程,調(diào)用terminate()方法關(guān)閉

this.webWorker1 = new WorkerA('./web.worker.js') 
this.webWorker1.terminate();

如果是在Work線程,可以調(diào)用close()方法進(jìn)行關(guān)閉

self.close();

主線程關(guān)閉 worker 線程的說(shuō)明

當(dāng)主線程調(diào)用worker.terminate()時(shí),Worker線程會(huì)被立即終止。

無(wú)論當(dāng)前事件循環(huán)中是否有任務(wù),包括微任務(wù)和宏任務(wù),都不會(huì)繼續(xù)執(zhí)行。

也就是說(shuō):如果我在點(diǎn)擊[導(dǎo)入excel]按鈕后,馬上又關(guān)閉點(diǎn)擊[關(guān)閉worker],那么不能夠正常導(dǎo)出表格。

Worker線程內(nèi)部關(guān)閉 worker 線程的說(shuō)明

當(dāng)Worker線程內(nèi)部調(diào)用self.close()時(shí),Worker線程并不會(huì)立即終止。

它會(huì)[繼續(xù)執(zhí)行當(dāng)前]事件循環(huán)中的任務(wù),但是[會(huì)阻止后續(xù)]事件循環(huán)的任務(wù)執(zhí)行。

也就是說(shuō):如果我在點(diǎn)擊[導(dǎo)入excel]按鈕后,馬上又關(guān)閉點(diǎn)擊[Worker內(nèi)部關(guān)閉Worker],仍然可以導(dǎo)出表格。

判斷用戶瀏覽器是否支持 worker

if (typeof Worker !== 'undefined') {
  console.log('瀏覽器支持 Web Workers');
} else {
  console.log('瀏覽器不支持 Web Workers');
}

Worker 線程引用其他js文件

有些時(shí)候,我們需要在worker文件中,引入其他模塊的文件。

可以通過(guò) importScripts() 方法來(lái)實(shí)現(xiàn),在 worker 中導(dǎo)入其他的模塊。這個(gè)地址是可以跨域的。

Worker 指定模塊類型

如果我們發(fā)現(xiàn)我們需要導(dǎo)出的方法使用的是ESModule 模式導(dǎo)出。

此時(shí)使用 importScripts() 方法引入他模塊,會(huì)報(bào)錯(cuò)。

此時(shí)需要指定模塊類型。

// main.js(主線程的代碼)
const worker = new Worker('/worker.js', {
    type: 'module'  // 指定 worker.js 的類型
});
// worker.js(worker線程的代碼)
import add from './utils.js'; // 導(dǎo)入外部js

self.addEventListener('message', e => { 
    postMessage(e.data);
});

add(1, 2);
// utils.js 使用了ESModule 模塊導(dǎo)出的 add 方法
export default add = (a, b) => a + b;

使用worker的注意事項(xiàng)

1,worker不能使用window上的dom操作,也不能獲取dom對(duì)象,dom相關(guān)的東西只有主線程有。worker只能做一些計(jì)算相關(guān)的操作

2,有的東西是無(wú)法通過(guò)主線程傳遞個(gè)子線程的。

比如:方法,dom節(jié)點(diǎn),一些對(duì)象里的特殊設(shè)置(freeze,getter,setter這些)所以vue的響應(yīng)式對(duì)象在傳遞之后就會(huì)變成普通對(duì)象

worker實(shí)際應(yīng)用案例

1,將語(yǔ)法檢查、代碼壓縮等任務(wù)放在 Worker 中執(zhí)行

2,圖像處理:比如使用Canvas處理圖片,進(jìn)行濾鏡

worker性能優(yōu)化建議

減少通信開銷:避免頻繁傳遞大量數(shù)據(jù),必要時(shí)使用 Transferable Objects(如 ArrayBuffer)

批量處理:對(duì)于大批量任務(wù),可批量創(chuàng)建 Worker 并行處理

常駐線程:對(duì)于頻繁使用的 Worker,可保持常駐而非重復(fù)創(chuàng)建

錯(cuò)誤處理:始終監(jiān)聽 onerror 事件,捕獲 Worker 內(nèi)部的異常

以上就是一文帶你掌握J(rèn)avaScript中worker的具體使用的詳細(xì)內(nèi)容,更多關(guān)于JavaScript worker用法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

怀集县| 巴楚县| 平泉县| 饶平县| 香河县| 临城县| 佛学| 慈溪市| 栾川县| 休宁县| 盖州市| 灵寿县| 普兰县| 磐石市| 搜索| 眉山市| 北宁市| 那曲县| 大安市| 叶城县| 改则县| 桦南县| 越西县| 靖西县| 余江县| 永寿县| 和平县| 额敏县| 蓬溪县| 海盐县| 澎湖县| 南川市| 内江市| 许昌县| 民勤县| 通江县| 乌鲁木齐县| 临海市| 巩留县| 石景山区| 佛坪县|