溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

web?worker在項目中怎么使用

發(fā)布時間:2022-09-21 15:33:05 來源:億速云 閱讀:122 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“web worker在項目中怎么使用”,在日常操作中,相信很多人在web worker在項目中怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”web worker在項目中怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

為什么JavaScript是單線程?

總所周知,JavaScript語言的特點是單線程,也就是說,同一個時間只能做一件事。那么,為什么JavaScript不能有多個線程呢?這樣能提高效率啊。

JavaScript的單線程,與它的用途有關(guān)。作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。比如,假定JavaScript同時有兩個線程,一個線程在某個DOM節(jié)點上添加內(nèi)容,另一個線程刪除了這個節(jié)點,這時瀏覽器應(yīng)該以哪個線程為準?

什么是Web Worker?

為了利用多核CPU的計算能力,HTML5提出Web Worker標準,允許JavaScript腳本創(chuàng)建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標準并沒有改變JavaScript單線程的本質(zhì)。

在worker線程中,雖然無法直接操作dom節(jié)點,也不能使用window對象的默認方法和屬性,但是仍然可以使用window對象下的東西,比如websocket,indexedDB等。

workers 和主線程間的數(shù)據(jù)傳遞通過這樣的消息機制進行——雙方都使用postMessage() 方法發(fā)送各自的消息,使用 onmessage 事件處理函數(shù)來響應(yīng)消息(消息被包含在Message事件的 data 屬性中)。這個過程中數(shù)據(jù)并不是被共享而是被復(fù)制。

關(guān)于web worker的兼容性問題,在can i use中查找一輪后發(fā)現(xiàn),基本目前所有主流的瀏覽器都支持了,因此放心食用,無需考慮兼容性的問題。

web?worker在項目中怎么使用

小試牛刀

前面學(xué)習(xí)了那么多武功秘籍,少俠們,確定不來一展身手嗎?

小羽這里簡單的寫了一個小demo,這個demo的內(nèi)容就是遞歸獲取斐波那契數(shù)列。會分為單線程和多線程模式,然后分別測試運行20次fb方法所需要的時間。

  • 單線程模式:利用for循環(huán)直接執(zhí)行20次fb,統(tǒng)計執(zhí)行時間

  • 多線程模式:利用for循環(huán),創(chuàng)建多個worker線程。并使用promise.all處理這些異步的worker線程,等待所有的worker執(zhí)行完成后,統(tǒng)計執(zhí)行時間

<!--
 * @Author: xiaoyu
 * @Description: 
 * @Date: 2022-05-08 08:40:54
 * @LastEditors: xiaoyu
 * @LastEditTime: 2022-06-29 23:19:40
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>web worker</title>
</head>
<script>
    const number = 20 // 運行次數(shù)
    // 多線程測試
    function workerTest() {
        console.log('%c 開始多線程測試 ', 'color:#fff; background:#00897b ')
        const workerList = []
        for (let i = 0; i < number; i++) {
            const workerItem = new Promise((resolve, reject) => {
                const myWorker = new Worker('worker.js')
                myWorker.postMessage({
                    function: 'fb',
                    data: 43
                })
                myWorker.onmessage = (e) => {
                    resolve(e.data)
                    // 關(guān)閉worker線程
                    myWorker.terminate()
                }
            })
            workerList.push(workerItem)
        }
        console.time('worker多線程執(zhí)行時間')
        Promise.all(workerList).then(res => {
            console.log(res)
            console.timeEnd('worker多線程執(zhí)行時間')
        })
    }
    function singleTest() {
        console.log('%c 開始單線程測試 ', 'color:#fff; background:#00897b ')
        function fb(n) {
            if (n === 1 || n === 2) {
                return 1;
            }
            return fb(n - 1) + fb(n - 2)
        }
        console.time('單線程執(zhí)行時間')
        for (let i = 0; i < number; i++) {
            const res = fb(43)
            console.log({
                data: res,
                name: 'single test'
            })
        }
        console.timeEnd('單線程執(zhí)行時間')
    }
</script>
<body>
    <button onclick="singleTest()">單線程測試</button>
    <button onclick="workerTest()">多線程測試</button>
</body>
</html>
/*
 * @Author: xiaoyu
 * @Description: worker 線程
 * @Date: 2022-05-08 08:41:30
 * @LastEditors: xiaoyu
 * @LastEditTime: 2022-06-29 23:17:44
 */
// 方法對象
const funcObj = {
  fb: (n) => {
    if(n===1 || n ===2){
      return 1;
    }
    return funcObj.fb(n-1) + funcObj.fb(n-2)
  }
}
// onmessage事件
onmessage = function(e){
  const {data} = e;
  const res = funcObj[data.function](data.data)
  // 將獲取的數(shù)據(jù)通過postMessage發(fā)送到主線程
  self.postMessage({
    data: res,
    name: 'worker test'
  })
  self.close()
}

打開任務(wù)管理器,點擊單線程測試按鈕進行單線程的測試??梢詮南聢D發(fā)現(xiàn),單線程的調(diào)用時間約為70s,cpu的調(diào)用基本上也就只是兩個核心在切換工作,小羽在多次測試后,其實是有多個核心在切換工作,不過單一時間只有一個核心是在滿載工作(遞歸獲取斐波那契數(shù)列)。

web?worker在項目中怎么使用

同樣是打開任務(wù)管理器,然后點擊多線程測試按鈕。此時咱們的cpu就不再偷懶了,直接16線程滿載運行,只需要7.9s就完成了20次遞歸獲取斐波那契數(shù)列。

咱們簡單的計算一下使用web worker多線程提升效果:(70750-7973)/7973 &asymp;7.87。即提升了7.87倍的效率。當然這是在8核16線程上的電腦上跑了,如果在核心數(shù)不同的cpu上這個倍數(shù)也是會發(fā)生相應(yīng)的變化

web?worker在項目中怎么使用

在單頁面應(yīng)用中使用

通過上面的例子,是不是so easy呀?

好啦,那咱們就算掌握了web worker的基本使用方法啦。

但是在react、vue等單頁面應(yīng)用中,webpack/vite通常會將js代碼打包成一個js文件。因此通過上面的new Worker('worker.js')的方式來新建worker,將會報訪問不到worker.js的錯誤。

所以,在單頁面應(yīng)用中,咱們該怎么使用web worker呢?

方案1:既然webpack/vite會將js的代碼打包成一個js文件,那咱們不讓它打包不就好了。而單頁面應(yīng)用的工程下,通常都是會有一個public的靜態(tài)資源目錄,咱們將worker.js放入其中即可。

方案2:webpack4及以下的版本可以使用worker-loader

方案3:webpack5/vite則可以使用new Worker(new URL('worker.js', import.meta.url))的方式

import React from 'react'
export default function WebWorkerTest() {
  const handleClick = () => {
    const number = 1
    const workerList = []
    console.log('%c 開始多線程測試 ', 'color:#fff; background:#00897b ')
    for (let i = 0; i < number; i++) {
      const workerItem = new Promise((resolve, reject) => {
        const myWorker = new Worker(new URL('../utils/fb.worker.ts', import.meta.url))
        myWorker.postMessage({
          function: 'fb',
          data: 43
        })
        myWorker.onmessage = (e) => {
          resolve(e.data)
          // 關(guān)閉worker線程
          myWorker.terminate()
        }
      })
      workerList.push(workerItem)
    }
    console.time('worker多線程執(zhí)行時間')
    Promise.all(workerList).then(res => {
      console.log(res)
      console.timeEnd('worker多線程執(zhí)行時間')
    })
  }
  return (
    <>
      <button onClick={handleClick}>vite/webpack5</button>
    </>
  )
}
// fb.worker.ts
// 方法對象
const funcObj = {
  fb: (n: number): number => {
    if (n === 1 || n === 2) {
      return 1;
    }
    return funcObj.fb(n - 1) + funcObj.fb(n - 2);
  },
};
// onmessage事件
onmessage = function (e) {
  const { data } = e;
  const res = funcObj[data.function](data.data);
  // 將獲取的數(shù)據(jù)通過postMessage發(fā)送到主線程
  self.postMessage({
    data: res,
    name: "worker test",
  });
  self.close();
};

注意事項

雖然web worker可以調(diào)用cpu的多線程,從而提高咱們頁面的性能。但是它不是隨便使用的,如果濫用web worker可能不僅不會得到性能的提升,還可能造成性能的損耗。

舉一個簡單的小栗子

如果咱們將遞歸獲取斐波那契數(shù)列第n位的方法,將傳入?yún)?shù)修改為第2位,這時候咱們再重跑單線程測試和多線程測試。

結(jié)果如下圖,咱們可以發(fā)現(xiàn)單線程模式下,獲取20次斐波那契數(shù)列第二位的時間僅需要1.5ms,而在多線程的情況下卻需要78ms。這是為什么呢?因為咱們每次創(chuàng)建worker線程以及possmessage通信都是需要損耗一些性能以及時間的。因此web worker是不可以濫用的哦,日常開發(fā)中,建議在需要消耗比較多的cpu運算能力的時候酌情使用。

web?worker在項目中怎么使用

到此,關(guān)于“web worker在項目中怎么使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI