您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關JavaScript Web Workers的構建塊及5個使用場景是什么的內容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。
這次我們會逐步講解 Web Workers,先說個簡單的概念,接著討論不同類型的 Web Workers,他們的組成部分是如何一起工作的,以及不同場景下它們各自優勢和限制。最后,提供5個正確使用 Web Workers 的場景。
正如我們前面文章討論的那樣,你應該知道 JavaScript 語言采用的是單線程模型。然而,JavaScript 也為開發人員提供了編寫異步代碼的機會。
以前的文章討論過異步編程,以及應該在什么時候使用它。
異步編程可以讓UI界面是響應式(渲染速度快)的,通過"代碼調度",讓需要請求時間的代碼先放到在 event loop中晚一點再執行,這樣就允許UI先行渲染展示。
異步編程的一個很好的用例就 AJAX 請求。由于請求可能花費大量時間,因此可以使用異步請求,在客戶端等待響應的同時還可以執行其他代碼。
然而,這帶來了一個問題——請求是由瀏覽器的WEB API處理的,但是如何使其他代碼是異步的呢?例如,如果成功回調中的代碼非常占用CPU:
var result = performCPUIntensiveCalculation();
如果 performCPUIntensiveCalculation
不是一個HTTP請求而是一個阻塞代碼(比如一個內容很多的for loop循環),就沒有辦法及時清空事件循環,瀏覽器的 UI 渲染就會被阻塞,頁面無法及時響應給用戶。
這意味著異步函數只能解決一小部分 JavaScript 語言單線程中的局限性問題。
在某些情況下,可以使用 setTimeout
對長時間運行的計算阻塞的,可以使用 setTimeout
暫時放入異步隊列中,從讓頁面得到更快的渲染。例如,通過在單獨的 setTimeout
調用中批處理復雜的計算,可以將它們放在事件循環中單獨的“位置”上,這樣可以爭取為 UI 渲染/響應的執行時間。
看一個簡單的函數,計算一個數字數組的平均值:
以下是重寫上述代碼并“模擬”異步性的方法:
function averageAsync(numbers, callback) { var len = numbers.length, sum = 0; if (len === 0) { return 0; } function calculateSumAsync(i) { if (i < len) { // Put the next function call on the event loop. setTimeout(function() { sum += numbers[i]; calculateSumAsync(i + 1); }, 0); } else { // The end of the array is reached so we're invoking the callback. callback(sum / len); } } calculateSumAsync(0); }
使用setTimeout函數,該函數將在事件循環中進一步添加計算的每個步驟。在每次計算之間,將有足夠的時間進行其他計算,從而可以讓瀏覽器進行渲染。
HTML5為我們帶來了很多新的東西,包括:
Web Worker 的作用,就是為 JavaScript 創造多線程環境,允許主線程創建 Worker 線程,將一些任務分配給后者運行。在主線程運行的同時,Worker 線程在后臺運行,兩者互不干擾。等到 Worker 線程完成計算任務,再把結果返回給主線程。這樣的好處是,一些計算密集型或高延遲的任務,被 Worker 線程負擔了,主線程(通常負責 UI 交互)就會很流暢,不會被阻塞或拖慢。
你可能會問:“JavaScript不是一個單線程的語言嗎?”
事實上 JavaScript 是一種不定義線程模型的語言。Web Workers 不是 JavaScript 的一部分,而是可以通過 JavaScript 訪問的瀏覽器特性。歷史上,大多數瀏覽器都是單線程的(當然,這已經改變了),大多數 JavaScript 實現都入發生在瀏覽器中。Web Workers 不是在 Node.JS 中實現的。Node.js 中有類似的集群(cluster)、子進程概念(child_process),他們也是多線程但是和 Web Workers 還是有區別 。
值得注意的是,規范 中提到了三種類型的 Web Workers:
專用 Workers 只能被創建它的頁面訪問,并且只能與它通信。以下是瀏覽器支持的情況:
共享 Workers 在同一源(origin)下面的各種進程都可以訪問它,包括:iframes、瀏覽器中的不同tab頁(一個tab頁就是一個單獨的進程,所以Shared Workers可以用來實現 tab 頁之間的交流)、以及其他的共享 Workers。以下是瀏覽器支持的情況:
Service Worker 功能:
在目前階段,Service Worker 的主要能力集中在網絡代理和離線緩存上。具體的實現上,可以理解為 Service Worker 是一個能在網頁關閉時仍然運行的 Web Worker。以下是瀏覽器支持的情況:
本文主要討論 專用 Workers,沒有特別聲明的話,Web Workers、Workers都是指代的專用 Workers。
Web Workers 一般通過腳本為 .js
文件來構建,在頁面中還通過了一些異步的 HTTP 請求,這些請求是完全被隱藏了的,你只需要調用 Web Worker API.
Worker 利用類線程間消息傳遞來實現并行性。它們保證界面的實時性、高性能和響應性呈現給用戶。
Web Workers 在瀏覽器中的一個獨立線程中運行。因此,它們執行的代碼需要包含在一個單獨的文件中。這一點很重要,請記住!
讓我們看看基本 Workers 是如何創建的:
var worker = new Worker('task.js');
Worker()
構造函數的參數是一個腳本文件,該文件就是 Worker 線程所要執行的任務。由于 Worker 不能讀取本地文件,所以這個腳本必須來自網絡。如果下載沒有成功(比如404錯誤),Worker 就會默默地失敗。
為了啟動創建的 Worker,需要調用 postMessage
方法:
worker.postMessage();
為了在 Web Worker 和創建它的頁面之間進行通信,需要使用 postMessage
方法或 Broadcast Channel。
新瀏覽器支持JSON對象作為方法的第一個參數,而舊瀏覽器只支持字符串。
來看一個示例,通過將 JSON 對象作為一個更“復雜”的示例傳遞,創建 Worker 的頁面如何與之通信。傳遞字符串跟傳遞對象的方式也是一樣的。
讓我們來看看下面的 HTML 頁面(或者更準確地說是它的一部分):
<button onclick="startComputation()">Start computation</button> <script> function startComputation() { worker.postMessage({'cmd': 'average', 'data': [1, 2, 3, 4]}); } var worker = new Worker('doWork.js'); worker.addEventListener('message', function(e) { console.log(e.data); }, false); </script>
然后這是 worker 中的 js 代碼:
self.addEventListener('message', function(e) { var data = e.data; switch (data.cmd) { case 'average': var result = calculateAverage(data); // 從數值數組中計算平均值的函數 self.postMessage(result); break; default: self.postMessage('Unknown command'); } }, false);
當單擊該按鈕時,將從主頁調用 postMessage
。postMessage 行將 JSON 對象傳給Worker。Worker 通過定義的消息處理程序監聽并處理該消息。
當消息到達時,實際的計算在worker中執行,而不會阻塞事件循環。Worker 檢查傳遞的事件參數 e
,像執行 JavaScript 函數一樣,處理完成后,把結果傳回給主頁。
在 Worker 作用域中,this 和 self 都指向 Worker 的全局作用域。
有兩種方法可以停止 Worker:從主頁調用worker.terminate()
或在worker
內部調用self.close()
。
Broadcast Channel API 允許同一原始域和用戶代理下的所有窗口,iFrames 等進行交互。也就是說,如果用戶打開了同一個網站的的兩個標簽窗口,如果網站內容發生了變化,那么兩個窗口會同時得到更新通知。
還是不明白?就拿 Facebook 作為例子吧,假如你現在已經打開 了Facebook 的一個窗口,但是你此時還沒有登錄,此時你又打開另外一個窗口進行登錄,那么你就可以通知其他窗口/標簽頁去告訴它們一個用戶已經登錄了并請求它們進行相應的頁面更新。
// Connection to a broadcast channel var bc = new BroadcastChannel('test_channel'); // Example of sending of a simple message bc.postMessage('This is a test message.'); // Example of a simple event handler that only // logs the message to the console bc.onmessage = function (e) { console.log(e.data); } // Disconnect the channel bc.close()
可以從下面這張圖,在視覺上來清晰地感受 Broadcast Channel:
Broadcast Channel 瀏覽器支持比較有限:
有兩種方式發送消息給Web Workers:
由于 JavaScript的多線程特性,Web工作者只能訪問JavaScript特性的一個子集。以下是它的一些特點:
Web Workers 由于具有多線程特性,因此只能訪問 JavaScript 特性的子集。 以下是可使用特性列表:
importScripts()
導入外部腳本遺憾的是,Web Workers 無法訪問一些非常關鍵的 JavaScript 特性:
這意味著 Web Worker 不能操作 DOM (因此也不能操作 UI)。有時這可能很棘手,但是一旦你了解了如何正確使用 Web Workers,你就會開始將它們作為單獨的“計算機”使用,而所有 UI 更改都將發生在你的頁面代碼中。 Workers 將為你完成所有繁重的工作,然后一旦完成再把結果返回給 page 頁面。
和 JavaScript 代碼一樣,Web workers 里拋出的錯誤,你也需要進行處理。當 Worker 執行過程中如果遇到錯誤,會觸發一個 ErrorEvent
事件。接口包含了三個有用的屬性來幫忙排查問題:
例子如下:
在這里,可以看到我們創建了一個 worker 并開始偵聽錯誤事件。
在 worker 內部(在 workerWithError.js
中),我們通過將未定義 x
乘以 2 來創建一個異常。異常被傳播到初始腳本,然后通過頁面監聽 error事件,對錯誤進行捕獲。
到目前為止,我們已經列出了 Web Workers 的優點和局限性。現在讓我們看看它們最強大的用例是什么:
Spell checking(拼寫檢查):一個基本的拼寫檢查程序的工作流程如下-程序讀取一個字典文件與一個正確拼寫單詞列表。字典被解析為一個搜索樹,以使實際的文本搜索更有效。當一個單詞被提供給檢查器時,程序檢查它是否存在于預先構建的搜索樹中。如果在樹中沒有找到該單詞,可以通過替換替換字符并測試它是否是有效的單詞(如果是用戶想要寫的單詞),為用戶提供替代拼寫。所有的這些處理過程都可以在 Web Worker中進行了,用戶可以不被阻塞的輸入詞匯和句子,Web Worker 在后臺校驗詞匯是否正確以及提供備選詞匯。
感謝各位的閱讀!關于JavaScript Web Workers的構建塊及5個使用場景是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。