<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
平時小夥伴們不是說日常的專案開發中,都是單純的搬磚,沒啥亮點嘛,那現在就來啦!
咱們今天就來聊聊web worker,這可是面試官最最最喜歡的的效能優化哦~
總所周知,JavaScript語言的特點是單執行緒,也就是說,同一個時間只能做一件事。那麼,為什麼JavaScript不能有多個執行緒呢?這樣能提高效率啊。
JavaScript的單執行緒,與它的用途有關。作為瀏覽器指令碼語言,JavaScript的主要用途是與使用者互動,以及操作DOM。這決定了它只能是單執行緒,否則會帶來很複雜的同步問題。比如,假定JavaScript同時有兩個執行緒,一個執行緒在某個DOM節點上新增內容,另一個執行緒刪除了這個節點,這時瀏覽器應該以哪個執行緒為準?
為了利用多核CPU的計算能力,HTML5提出Web Worker標準,允許JavaScript指令碼建立多個執行緒,但是子執行緒完全受主執行緒控制,且不得操作DOM。所以,這個新標準並沒有改變JavaScript單執行緒的本質。
在worker執行緒中,雖然無法直接操作dom節點,也不能使用window物件的預設方法和屬性,但是仍然可以使用window物件下的東西,比如websocket,indexedDB等。
workers 和主執行緒間的資料傳遞通過這樣的訊息機制進行——雙方都使用postMessage() 方法傳送各自的訊息,使用 onmessage 事件處理常式來響應訊息(訊息被包含在Message事件的 data 屬性中)。這個過程中資料並不是被共用而是被複制。
關於web worker的相容性問題,在can i use中查詢一輪後發現,基本目前所有主流的瀏覽器都支援了,因此放心食用,無需考慮相容性的問題。
前面學習了那麼多武功祕籍,少俠們,確定不來一展身手嗎?
小羽這裡簡單的寫了一個小demo,這個demo的內容就是遞迴獲取斐波那契數列。會分為單執行緒和多執行緒模式,然後分別測試執行20次fb方法所需要的時間。
<!-- * @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 // 執行次數 // 多執行緒測試 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) // 關閉worker執行緒 myWorker.terminate() } }) workerList.push(workerItem) } console.time('worker多執行緒執行時間') Promise.all(workerList).then(res => { console.log(res) console.timeEnd('worker多執行緒執行時間') }) } 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('單執行緒執行時間') for (let i = 0; i < number; i++) { const res = fb(43) console.log({ data: res, name: 'single test' }) } console.timeEnd('單執行緒執行時間') } </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) // 將獲取的資料通過postMessage傳送到主執行緒 self.postMessage({ data: res, name: 'worker test' }) self.close() }
開啟工作管理員,點選單執行緒測試按鈕進行單執行緒的測試。可以從下圖發現,單執行緒的呼叫時間約為70s,cpu的呼叫基本上也就只是兩個核心在切換工作,小羽在多次測試後,其實是有多個核心在切換工作,不過單一時間只有一個核心是在滿載工作(遞迴獲取斐波那契數列)。
同樣是開啟工作管理員,然後點選多執行緒測試按鈕。此時咱們的cpu就不再偷懶了,直接16執行緒滿載執行,只需要7.9s就完成了20次遞迴獲取斐波那契數列。
咱們簡單的計算一下使用web worker多執行緒提升效果:(70750-7973)/7973 ≈7.87。即提升了7.87倍的效率。當然這是在8核16執行緒上的電腦上跑了,如果在核心數不同的cpu上這個倍數也是會發生相應的變化
通過上面的例子,是不是so easy呀?
好啦,那咱們就算掌握了web worker的基本使用方法啦。
但是在react、vue等單頁面應用中,webpack/vite通常會將js程式碼打包成一個js檔案。因此通過上面的new Worker('worker.js')的方式來新建worker,將會報存取不到worker.js的錯誤。
所以,在單頁面應用中,咱們該怎麼使用web worker呢?
方案1:既然webpack/vite會將js的程式碼打包成一個js檔案,那咱們不讓它打包不就好了。而單頁面應用的工程下,通常都是會有一個public的靜態資源目錄,咱們將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) // 關閉worker執行緒 myWorker.terminate() } }) workerList.push(workerItem) } console.time('worker多執行緒執行時間') Promise.all(workerList).then(res => { console.log(res) console.timeEnd('worker多執行緒執行時間') }) } 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); // 將獲取的資料通過postMessage傳送到主執行緒 self.postMessage({ data: res, name: "worker test", }); self.close(); };
雖然web worker可以呼叫cpu的多執行緒,從而提高咱們頁面的效能。但是它不是隨便使用的,如果濫用web worker可能不僅不會得到效能的提升,還可能造成效能的損耗。
舉一個簡單的小栗子
如果咱們將遞迴獲取斐波那契數列第n位的方法,將傳入引數修改為第2位,這時候咱們再重跑單執行緒測試和多執行緒測試。
結果如下圖,咱們可以發現單執行緒模式下,獲取20次斐波那契數列第二位的時間僅需要1.5ms,而在多執行緒的情況下卻需要78ms。這是為什麼呢?因為咱們每次建立worker執行緒以及possmessage通訊都是需要損耗一些效能以及時間的。因此web worker是不可以濫用的哦,日常開發中,建議在需要消耗比較多的cpu運算能力的時候酌情使用。
本文通過了幾個簡單的小栗子,帶大家學習web worker的基本知識,使用方法,以及需要注意的事項。小夥伴們在日常的開發中可以按需嘗試哦,讓自己的專案中多些亮點,也可以讓面試官眼前一亮哦。
更多關於web worker使用的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45