摘要:異步編程通過在事件循環中調度要稍后執行的部分代碼來使應用程序能夠響應,從而允許首先執行渲染。工作人員將通過定義的消息處理程序處理該消息。的應用場景到目前為止,我們列出了的優勢和局限性。
這一次我們將分拆Web Workers:我們將提供一個概述,討論不同類型的workers,他們的組成部分如何共同發揮作用,以及他們在不同情況下提供的優勢和局限性。最后,我們將提供5個用例,其中Web Workers將是不錯的選擇。
您應該已經熟悉JavaScript在單個線程上運行的事實,因為我們之前已經詳細討論過它。但是,JavaScript也為開發人員提供了編寫異步代碼的機會。
異步編程的局限性我們之前已經討論過異步編程,何時應該使用它。
異步編程通過在事件循環中“調度”要稍后執行的部分代碼來使應用程序UI能夠響應,從而允許首先執行UI渲染。
異步編程的一個很好的用例是制作AJAX請求。 由于請求可能需要很長時間,因此可以異步制作請求,并且在客戶端等待響應時,可以執行其他代碼。
// This is assuming that you"re using jQuery jQuery.ajax({ url: "https://api.example.com/endpoint", success: function(response) { // Code to be executed when a response arrives. } });
但是,這會帶來一個問題 - 請求由瀏覽器的WEB API處理,但其他代碼如何可以異步? 例如,如果成功回調中的代碼是CPU密集型的:
var result = performCPUIntensiveCalculation();
如果performCPUIntensiveCalculation不是一個HTTP請求,而是一個阻塞代碼(例如一個巨大的for循環),則無法釋放事件循環并解除瀏覽器的用戶界面 - 它會凍結并對用戶無響應。
這意味著異步函數僅解決JavaScript語言的單線程局限性的一小部分。
在某些情況下,通過使用setTimeout,您可以在從更長時間運行的計算中解除UI的情況下取得良好結果。例如,通過在獨立的setTimeout調用中對復雜的計算進行批處理,您可以將它們置于事件循環中的多帶帶“位置”,這樣就可以獲得UI渲染/響應性所需的時間。
我們來看看一個計算數值數組平均值的簡單函數:
function average(numbers) { var len = numbers.length, sum = 0, i; if (len === 0) { return 0; } for (i = 0; i < len; i++) { sum += numbers[i]; } return sum / len; }
這就是你如何重寫上面的代碼并“模擬”異步性:
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函數,該函數將在事件循環的更下方添加計算的每個步驟。 在每次計算之間,將有足夠的時間進行其他計算,這是解凍瀏覽器所必需的。
Web Workers 扭轉局面HTML5給我們帶來了很多很棒的東西,包括:
SSE(我們已經在之前的文章中描述并與WebSockets進行了比較)
地理位置
應用程序緩存
本地存儲
拖放
Web Worker
Web Workers是瀏覽器內的線程,可用于執行JavaScript代碼而不會阻止事件循環。
這真是太神奇了。 JavaScript的整個范例基于單線程環境的思想,但在這里來自網絡工作者(Web Workers),它解除了(部分)這種限制。
Web Workers允許開發人員將長時間運行和計算密集型任務放在后臺,而不會阻止用戶界面,從而使您的應用程序更具響應能力。更重要的是,為了解決事件循環的問題,不需要使用setTimeout技巧。
下面是一個簡單的演示,顯示了在有和沒有Web Workers的情況下對數組進行排序的區別。
Web Worker概述Web Workers允許您執行諸如啟動長時間運行的腳本來處理計算密集型任務,但不會阻止UI。實際上,這一切都是平行進行的。Web Workers真正是多線程的。
你可能會說 - “JavaScript不是單線程語言嗎?”。
當你意識到JavaScript是一種沒有定義線程模型的語言時,這應該是你的"aha!"時刻。 Web Workers不是JavaScript的一部分,它們是可以通過JavaScript訪問的瀏覽器功能。大多數瀏覽器歷來都是單線程的(當然,這已經改變了),并且大多數JavaScript實現都發生在瀏覽器中。 Web Worker沒有在Node.JS中實現 - 它有一個“cluster”或“child_process”的概念,有點不同。
值得注意的是,這個規范提到了三種類型的Web Workers:
Dedicated Worker
Shared Worker
Service Worker
Dedicated Worker專用Web Worker由主進程實例化,并且只能與其進行通信。
共享工作人員可以通過運行在同一來源的所有進程(不同的瀏覽器選項卡,iframe或其他共享工作人員)訪問。
服務工作人員是一個事件驅動的工作人員,針對原點和路徑進行了注冊。 它可以控制與之關聯的網頁/網站,攔截并修改導航和資源請求,并以非常細化的方式緩存資源,從而使您可以很好地控制應用在某些情況下的行為方式(例如,當網絡不是可用。)
在這篇文章中,我們將關注Dedicated Workers(專職工作者)并將他們稱為“(Web Workders)網絡工作者”或“(Workers)工作者”。
Web Workders 如何工作Web Workers被實現為.js文件,這些文件通過頁面中的異步HTTP請求提供。 Web Worker API完全隱藏了這些請求。
工作人員利用類似線程的消息傳遞來實現并行性。 它們非常適合保持您的用戶界面的最新性,性能和響應能力。
Web工作人員在瀏覽器中的獨立線程中運行。 因此,它們執行的代碼需要包含在多帶帶的文件中。 記住這一點非常重要。
讓我們看看如何創建一個基本的工作人員:
var worker = new Worker("task.js");
如果“task.js”文件存在且可訪問,瀏覽器將產生一個新的線程,以異步方式下載文件。 下載完成后,它將被執行,工作人員將開始工作。
如果提供的文件路徑返回404,工作人員將自動失敗。
為了啟動創建的worker,你需要調用postMessage方法:
worker.postMessage();網絡工作者通信
為了在Web Worker和創建它的頁面之間進行通信,您需要使用postMessage方法或廣播頻道。
postMessage方法較新的瀏覽器支持將JSON對象作為該方法的第一個參數,而舊版瀏覽器只支持一個字符串。
讓我們看一個創建worker的頁面如何與它進行通信的例子,通過傳遞一個JSON對象作為一個更“復雜”的例子。 傳遞一個字符串是完全一樣的。
我們來看看下面的HTML頁面(或者更精確一些):
這就是我們的工作人員腳本的外觀:
self.addEventListener("message", function(e) { var data = e.data; switch (data.cmd) { case "average": var result = calculateAverage(data); // Some function that calculates the average from the numeric array. self.postMessage(result); break; default: self.postMessage("Unknown command"); } }, false);
點擊按鈕后,將從主頁面調用postMessage。 worker.postMessage行將JSON對象傳遞給worker,并添加cmd和數據鍵及其各自的值。 工作人員將通過定義的消息處理程序處理該消息。
當消息到達時,實際的計算正在工作者中執行,而不會阻塞事件循環。 工作人員正在檢查傳遞的事件e并執行,就像標準的JavaScript函數一樣。 完成后,結果會傳回主頁面。
在一名工人的背景下,自我和這一點都指向了工人的全球范圍。
有兩種方法可以阻止工作人員:通過從主頁面調用worker.terminate()或在worker本身內部調用self.close()。
廣播頻道廣播頻道是更通用的通信API。 它允許我們將消息廣播到共享相同來源的所有上下文。 所有瀏覽器選項卡,iframe或從同一來源提供服務的工作人員都可以發送和接收消息:
// 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()
在視覺上,你可以看到廣播頻道的樣子,使其更加清晰:
雖然廣播頻道的瀏覽器支持有限,
消息的大小有兩種方式將消息發送給Web Workers:
復制消息:消息被序列化,復制,發送,然后在另一端解除序列化。頁面和工作人員不共享同一個實例,所以最終結果是每次傳遞都會創建一個副本。大多數瀏覽器通過自動JSON編碼/解碼任何一端的值來實現此功能。正如所料,這些數據操作為消息傳輸增加了大量的開銷。信息越大,發送時間越長。
轉發郵件:這意味著原始發件人在發送后不能再使用它。傳輸數據幾乎是瞬間的。限制是只有ArrayBuffer可以轉讓。
Web Workers可用的功能由于Web Worker的多線程特性,Web Worker只能訪問JavaScript特性的一個子集。以下是功能列表:
navigator對象
location對象(只讀)
XMLHttpRequest
setTimeout()/ clearTimeout()和setInterval()/ clearInterval()
應用程序緩存
使用importScripts()導入外部腳本
創建其他Web Workers
Web Worker限制可悲的是,Web Workers沒有訪問一些非常關鍵的JavaScript特性:
DOM(它不是線程安全的)
窗口對象
文檔對象
父對象
這意味著Web Worker不能操縱DOM(以及UI)。它有時可能會非常棘手,但是一旦您學會如何正確使用Web Workers,您將開始將它們作為多帶帶的“計算機”使用,而所有UI更改將發生在您的頁面代碼中。工作人員將為您完成所有繁重的工作,一旦工作完成,您會將結果傳遞給對UI進行必要更改的頁面。
處理錯誤與任何JavaScript代碼一樣,您需要處理在Web Workers中引發的任何錯誤。如果在執行工作時發生錯誤,則會觸發ErrorEvent。該接口包含三個有用的屬性,用于確定出錯的地方:
filename - 導致錯誤的工作者腳本的名稱
lineno - 發生錯誤的行號
message - 錯誤的描述
這是一個例子:
function onError(e) { console.log("Line: " + e.lineno); console.log("In: " + e.filename); console.log("Message: " + e.message); } var worker = new Worker("workerWithError.js"); worker.addEventListener("error", onError, false); worker.postMessage(); // Start worker without a message.
self.addEventListener("message", function(e) { postMessage(x * 2); // Intentional error. "x" is not defined. };
在這里,您可以看到我們創建了一geWorker并開始監聽錯誤事件。
在worker的內部(在workerWithError.js中),我們通過將x乘以2來創建一個有意的異常,而未在該范圍中定義x。 異常傳播到初始腳本,并且正在調用有關錯誤信息的onError。
Web Workers的應用場景到目前為止,我們列出了Web Workers的優勢和局限性。現在讓我們看看最佳應用場景:
光線追蹤:光線追蹤是一種通過將光線追蹤為像素來生成圖像的渲染技術。光線追蹤使用CPU密集型數學計算來模擬光線路徑。這個想法是模擬反射,折射,材質等一些效果。所有這些計算邏輯都可以添加到Web Worker中以避免阻塞UI線程。更好的是 - 您可以輕松地將幾個工作人員(以及多個CPU之間)之間的圖像渲染分開。這里是使用Web Workers進行光線追蹤的簡單演示 - https://nerget.com/rayjs-mt/r...。
加密:由于對個人和敏感數據的監管日益嚴格,端到端加密越來越受歡迎。加密可能是一件非常耗時的事情,特別是如果有很多數據必須經常加密(例如在將數據發送到服務器之前)。這是一個非常好的場景,可以使用Web Worker,因為它不需要訪問DOM或任何想象的東西 - 這是純粹的算法來完成他們的工作。一旦進入工作人員,它對最終用戶而言是無縫的,并且不會影響他們的體驗。
預取數據:為了優化您的網站或Web應用程序并縮短數據加載時間,您可以利用Web Workers預先加載和存儲一些數據,以便稍后在需要時使用它。在這種情況下,Web Workers是驚人的,因為它們不會影響您的應用的用戶界面,而不像工作時沒有工作人員那樣。
漸進式Web應用程序:即使網絡連接不穩定,它們也必須快速加載。這意味著數據必須存儲在本地瀏覽器中。這是IndexDB或類似的API進場的地方。基本上,需要客戶端存儲。為了在不阻塞UI線程的情況下使用,工作必須在Web Workers中完成。那么,就IndexDB而言,有一個異步API,即使沒有工作人員也可以執行此操作,但之前有一個同步API(可能會再次引入),只能在工作人員中使用。
拼寫檢查:基本拼寫檢查程序按以下方式工作 - 程序讀取帶有拼寫正確單詞列表的字典文件。正在將字典解析為搜索樹以使實際的文本搜索效率更高。當一個單詞被提供給檢查器時,程序檢查它是否存在于預先構建的搜索樹中。如果在樹中沒有找到該單詞,則可以通過替代字符并測試它是否是有效的單詞 - 如果它是用戶想要寫的單詞來為用戶提供替代拼寫。所有這些處理都可以輕松卸載到Web Worker中,以便用戶可以在沒有任何UI阻塞的情況下鍵入單詞和句子,而工作人員則執行所有搜索和提供建議。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107760.html
摘要:最后,我們將會介紹個的使用場景。異步編程的局限性前面我們了解到異步編程及其使用時機。請求是一個很好的異步編程的使用場景。整個是基于單線程環境的而部分可以突破這方面的限制。最佳使用場景迄今為止,我們列舉了的長處及其限制。 Web Workers 分類及 5 個使用場景 原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協議共享,BY Troland。 這是 JavaScri...
摘要:最后,提供個正確使用的場景。異步編程的一個很好的用例就請求。這意味著異步函數只能解決一小部分語言單線程中的局限性問題。中有類似的集群子進程概念,他們也是多線程但是和還是有區別。可用的特性由于的多線程特性,工作者只能訪問特性的一個子集。 showImg(https://segmentfault.com/img/bVblS8J?w=400&h=298); 這是專門探索 JavaScript...
摘要:的生命周期的生命周期與頁面完全分離。換句話說,這個將為這個域中的所有內容接收事件。這不是必要的,但絕對是推薦的。新的將啟動并且安裝事件將被移除。使用,可以很容易被劫持連接并偽造響應。后臺同步允許延遲操作,直到用戶具有穩定的連接。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第8篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前...
摘要:為了方便大家共同學習,整理了之前博客系列的文章,目前已整理是如何工作這個系列,可以請猛戳博客查看。以下列出該系列目錄,歡迎點個星星,我將更友動力整理理優質的文章,一起學習。 為了方便大家共同學習,整理了之前博客系列的文章,目前已整理 JavaScript 是如何工作這個系列,可以請猛戳GitHub博客查看。 以下列出該系列目錄,歡迎點個星星,我將更友動力整理理優質的文章,一起學習。 J...
閱讀 958·2022-06-21 15:13
閱讀 1848·2021-10-20 13:48
閱讀 1029·2021-09-22 15:47
閱讀 1365·2019-08-30 15:55
閱讀 3112·2019-08-30 15:53
閱讀 519·2019-08-29 12:33
閱讀 711·2019-08-28 18:15
閱讀 3458·2019-08-26 13:58