亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

JavaScript 工作原理之七-Web Workers 分類及 5 個使用場景

cartoon / 1589人閱讀

摘要:最后,我們將會介紹個的使用場景。異步編程的局限性前面我們了解到異步編程及其使用時機。請求是一個很好的異步編程的使用場景。整個是基于單線程環(huán)境的而部分可以突破這方面的限制。最佳使用場景迄今為止,我們列舉了的長處及其限制。

Web Workers 分類及 5 個使用場景
原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。

這是 JavaScript 工作原理的第七章。

本系列持續(xù)更新中,Github 地址請查閱這里。

現(xiàn)在,我們將會剖析 Web Workers:我們將會綜合比較不同類型的 workers,如何組合運用他們的構(gòu)建模塊來進行開發(fā)以及不同場景下各自的優(yōu)缺點。最后,我們將會介紹 5 個 Web Workder 的使用場景。

在前面的詳細介紹的文章中你已經(jīng)清楚地了解到 JavaScript 是單線程的事實。然而,JavaScript 也允許開發(fā)者編寫異步代碼。

異步編程的局限性

前面我們了解到異步編程及其使用時機。

異步編程通過調(diào)度部分代碼使之在事件循環(huán)中延遲執(zhí)稈,這樣就允許優(yōu)先渲染程序界面,從而讓程序運行流暢。

AJAX 請求是一個很好的異步編程的使用場景 。因為請求可能會花很長的時間,所以可以異步執(zhí)行它們,然后在客戶端等待數(shù)據(jù)返回的同時,運行其它代碼。

// 假設(shè)使用 jQuery
jQuery.ajax({
    url: "https://api.example.com/endpoint",
    success: function(response) {
            // 當(dāng)數(shù)據(jù)返回時候的代碼
    }
});

然而,這里會產(chǎn)生一個問題-AJAX 請求是由瀏覽器網(wǎng)頁 API 進行處理的,可以異步執(zhí)行其它代碼嗎?比如,假設(shè)成功回調(diào)的代碼是 CPU 密集型的:

var result = performCPUIntensiveCalculation();

如果 performCPUIntensiveCalculation 不是一個 HTTP 請求而是一個會阻塞界面渲染的代碼(比如大量的 for 循環(huán)),這樣就沒有辦法釋放事件循環(huán)和瀏覽器的 UI-瀏覽器會被凍結(jié)住且失去響應(yīng)。

這意味著,異步函數(shù)只是是解決了一部分 JavaScript 的單線程限制。

在某些情況下,你可以通過使用 setTimeout 來很好地解決由于長時間計算所造成的 UI 阻塞。比如,通過把一個復(fù)雜的計算批量拆分為若干個setTimeout 調(diào)用 ,把它們放在事件循環(huán)的不同位置執(zhí)行,然后這樣就可以使得 UI 有時間進行渲染及響應(yīng)。

讓我們看一個計算數(shù)值數(shù)組的平均值的簡單函數(shù)。

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) {
            // 在事件循環(huán)中調(diào)用下一個函數(shù)
            setTimeout(function() {
                sum += numbers[i];
                calculateSumAsync(i + 1);
            }, 0);
        } else {
             // 到達數(shù)組末尾,調(diào)用回調(diào)
            callback(sum / len);
        }
    }

    calculateSumAsync(0);
}

這里利用 setTimeout 函數(shù)在事件循環(huán)中循序添加每一次計算。在每一次計算之間,將會有充足的時間來進行其它的計算和解凍瀏覽器。

Web Workders 來救場

HTML5 給我們帶了很多開箱即用的好用的功能,包括:

SSE(之前文章中提到過并且和 WebSockets 進行了比較)

Geolocation

Application cache

Local Storage

Drag and Drop

Web Workers

Web Workers 是瀏覽器內(nèi)置的線程所以可以被用來執(zhí)行非阻塞事件循環(huán)的 JavaScript 代碼。

屌爆了。整個 JavaScript 是基于單線程環(huán)境的而 Web Workers (部分)可以突破這方面的限制。

Web Workers 允許開發(fā)者把長時間運行和密集計算型的任務(wù)放在后臺執(zhí)行而不會阻塞 UI,這會使得應(yīng)用程序運行得更加流暢。另外,這樣就不用再使用 setTimeout 的黑科技來防止阻塞事件循環(huán)了。

這里有一個展示使用和未使用 Web Workers 來進行數(shù)組排序的區(qū)別的示例。

Web Workers 概覽

Web Workers 允許你做諸如運行處理 CPU 計算密集型任務(wù)的耗時腳本而不會阻塞 UI 的事情。事實上,所有這些操作都是并行執(zhí)行的。Web Workers 是真正的多線程。

你或許會有疑問-『難道 JavaScript 不是單線程的嗎?』。

當(dāng)你意識到 JavaScript 是一門沒有定義線程模型的語言的時候,或許你會感覺非常的驚訝。Web Workers 并不是 JavaScript 的一部分,他們是可以通過 JavaScript 進行操作的瀏覽器功能之一。以前,大多數(shù)的瀏覽器是單線程的(當(dāng)然,現(xiàn)在已經(jīng)變了),而且大多數(shù)的 JavaScript 功能是在瀏覽器端實現(xiàn)完成的。Node.js 沒有實現(xiàn) Web Workers -它有 『cluster』和 『child_process』的概念,這兩者和 Web Workers 有些許差異。

值得注意的是,規(guī)范中有三種類型的 Web Workers:

Dedicated Workers

Shared Workers

Service workers

Dedicated Workers

Dedicated Web Workers 是由主進程實例化并且只能與之進行通信

Dedicated Workers 瀏覽器支持情況

Shared Workers

Shared workers 可以被運行在同源的所有進程訪問(不同的瀏覽的選項卡,內(nèi)聯(lián)框架及其它shared workers)。

Shared Workers 瀏覽器支持情況

Service Workers

Service Worker 是一個由事件驅(qū)動的 worker,它由源和路徑組成。它可以控制它關(guān)聯(lián)的網(wǎng)頁,解釋且修改導(dǎo)航,資源的請求,以及一種非常細粒度的方式來緩存資源以讓你非常靈活地控制程序在某些情況下的行為(比如網(wǎng)絡(luò)不可用)。

Service Workers 瀏覽器支持情況

本篇文章,我們將會專注于 Dedicated Workers 并以 『Web Workers』或者 『Workers』來稱呼它。

Web Workers 運行原理

Web Workers 是以加載 .js 文件的方式實現(xiàn)的,這些文件會在頁面中異步加載。這些請求會被 Web Worker API 完全隱藏。

Workers 使用類線程的消息傳輸-獲取模式。它們非常適合于為用戶提供最新的 UI ,高性能及流暢的體驗。

Web Workers 運行于瀏覽器的一個隔離線程之中。因此,他們所執(zhí)行的代碼必須被包含在一個多帶帶的文件之中。請謹(jǐn)記這一特性。

讓我們看如何創(chuàng)建初始化 worker 吧:

var worker = new Worker("task.js");

如果 『task.js』文件存在且可訪問,瀏覽器會生成一個線程來異步下載文件。當(dāng)下載完成的時候,文件會立即執(zhí)行然后 worker 開始運行。萬一文件不存在,worker 會運行失敗且沒有任何提示。

為了啟動創(chuàng)建的 worker,你需要調(diào)用 postMessage 方法:

worker.postMessage();
Web Worker 通信

為了在 Web Worker 和 創(chuàng)建它的頁面間進行通信,你得使用 postMessage 方法或者一個廣播信道。

postMessage 方法

最新的瀏覽器支持方法的第一參數(shù)為一個 JSON 對象而舊的瀏覽器只支持字符串。

讓我們來看一個例子,通過往 worker 的方法的第一個參數(shù)傳入更為復(fù)雜的 JSON 對象來理解其創(chuàng)建者頁面是如何與之進行來回通信的。傳入字符串與之類似。

讓我們看下以下的 HTML 頁面(或者更準(zhǔn)確地說是 HTML 頁面的一部分)



worker 的腳本如下:

self.addEventListener("message", function(e) {
  var data = e.data;
  switch (data.cmd) {
    case "average":
      var result = calculateAverage(data); // 某個數(shù)值數(shù)組中計算平均值的函數(shù)
      self.postMessage(result);
      break;
    default:
      self.postMessage("Unknown command");
  }
}, false);

當(dāng)點擊按鈕,會在主頁面調(diào)用 postMessage 方法。

worker.postMessage 行代碼會把包含 cmddata 屬性及其各自屬性值的 JSON 對象傳入 worker。worker 通過定義監(jiān)聽 message 事件來處理傳過來的消息。

當(dāng)接收到消息的時候,worker 會執(zhí)行實際的計算而不會阻塞事件循環(huán)。worker 會檢查傳進來的 e 事件,然后像一個標(biāo)準(zhǔn)的 JavaScript 函數(shù)那樣運行。當(dāng)運行結(jié)束,傳回主頁面計算結(jié)果。

在 worker 的上下文中,selfthis 都指向 worker 的全局作用域。

有兩種方法來中斷 woker 的執(zhí)行:主頁面中調(diào)用 worker.terminate() 或者在 workder 內(nèi)部調(diào)用 self.close()
廣播信道

Broadcast Channel 是更為普遍的通信接口。它允許我們向共享同一個源的所有上下文發(fā)送消息。同一個源下的所有的瀏覽器選項卡,內(nèi)聯(lián)框架或者 workers 都可以發(fā)送和接收消息:

// 連接到一個廣播信道
var bc = new BroadcastChannel("test_channel");

// 發(fā)送簡單信息示例
bc.postMessage("This is a test message.");

// 一個在控制臺打印消息的簡單事件處理程序示例
// logs the message to the console
bc.onmessage = function (e) { 
  console.log(e.data); 
}

// 關(guān)閉信道
bc.close()

視覺上看,你可以通過廣播信道的圖例以更加深刻的理解它。

所有的瀏覽器上下文都是同源的

然而,廣播信道瀏覽器兼容性不太好:

消息大小

有兩種向 Web Workers 發(fā)送消息的方法:

復(fù)制消息:消息被序列化,復(fù)制,然后發(fā)送出去,接著在接收端反序列化。頁面和 worker 沒有共享一個相同的消息實例,所以在每次傳遞消息過程中最后的結(jié)果都是復(fù)制的。大多數(shù)瀏覽器是通過在任何一端自動進行 JSON 編碼/解碼消息值來實現(xiàn)這一功能。正如所預(yù)料的那樣,這些對于數(shù)據(jù)的操作顯著增加了消息傳送的性能開銷。消息越大,傳送的時間越長。

消息傳輸:這意味著最初的消息發(fā)送者一發(fā)送即不再使用()。數(shù)據(jù)傳輸非常的快。唯一的限制即只能傳輸 ArrayBuffer 數(shù)據(jù)對象。

Web Workers 的可用功能

由于 Web Workers 的多線程特性,它只能使用一部分 JavaScript 功能。以下是可使用的功能列表:

navigator 對象

location 對象(只讀)

XMLHttpRequest

setTimeout()/clearTimeout()setInterval()/clearInterval()

Application Cache

使用 importScripts 來引用外部腳本

創(chuàng)建其它 web workers

Web Worker 的局限性

令人沮喪的是,Web Workers 不能夠訪問一些非常關(guān)鍵的 JavaScript 功能:

DOM(非線程安全的)

window 對象

document 對象

parent 對象

這意味著 Web Worker 不能夠操作 DOM(因此不能更新 UI)。有時候,這會讓人很蛋疼,不過一旦你學(xué)會如何合理地使 Web Workers,你就會把它當(dāng)成多帶帶的『計算機器』來使用而用其它頁面代碼來操作 UI。Workers 將會為你完成繁重的計算任務(wù)然后一旦任務(wù)完成,會把結(jié)果傳到頁面中并對界面進行必要的更新。

錯誤處理

和任何 JavaScript 代碼一樣,你會想要處理 Web Workers 中的任何錯誤。當(dāng)在 worker 執(zhí)行過程中有錯誤發(fā)生的時候,會觸發(fā) ErrorEvent 事件。這個接口包含三個有用的屬性來指出錯誤的地方:

filename-引起錯誤的 worker 腳本名稱

lineno-引起錯誤的代碼行數(shù)

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(); // 啟動 worker 而不帶任何消息
self.addEventListener("message", function(e) {
  postMessage(x * 2); // 意圖錯誤. "x" 未定義
};

這里,你可以看到我們創(chuàng)建了一個 worker 然后開始監(jiān)聽 error 事件。

在 worker 中(在 workerWithError 中),我們通過未在作用域中定義的 x 乘以 2 來創(chuàng)建一個意圖錯誤。異常會傳播到初始化腳本(即主頁面中)然后調(diào)用 onError 并傳入關(guān)于錯誤的信息。

Web Workers 最佳使用場景

迄今為止,我們列舉了 Web Workers 的長處及其限制。讓我們看看他們的最佳使用場景:

射線追蹤:射線追蹤是一項通過追蹤光線的路徑作為像素來生成圖片的渲染技術(shù)。Ray tracing 使用 CPU 密集型計算來模仿光線的路徑。思路即模仿一些諸如反射,折射,材料等的效果。所有的這些計算邏輯可以放在 Web Worker 中以避免阻塞 UI 線程。甚至更好的方法即-你可以輕易地把把圖片的渲染拆分在幾個 workers 中進行(即在各自的 CPU 中進行計算,意思是說利用多個 CPU 來進行計算,可以參考下 nodejs 的 api)。這里有一個使用 Web Workers 來進行射線追蹤的簡單示例-h(huán)ttps://nerget.com/rayjs-mt/r...。

加密:端到端的加密由于對保護個人和敏感數(shù)據(jù)日益嚴(yán)格的法律規(guī)定而變得越來越流行。加密有時候會非常地耗時,特別是如果當(dāng)你需要經(jīng)常加密很多數(shù)據(jù)的時候(比如,發(fā)往服務(wù)器前加密數(shù)據(jù))。這是一個使用 Web Worker 的絕佳場景,因為它并不需要訪問 DOM 或者利用其它魔法-它只是純粹使用算法進行計算而已。一旦在 worker 進行計算,它對于用戶來說是無縫地且不會影響到用戶體驗。

預(yù)取數(shù)據(jù):為了優(yōu)化網(wǎng)站或者網(wǎng)絡(luò)應(yīng)用及提升數(shù)據(jù)加載時間,你可以使用 Workers 來提前加載部分?jǐn)?shù)據(jù)以備不時之需。不像其它技術(shù),Web Workers 在這種情況下是最棒噠,因為它不會影響程序的使用體驗。

漸進式網(wǎng)絡(luò)應(yīng)用:即使在網(wǎng)絡(luò)不穩(wěn)定的情況下,它們必須快速加載。這意味著數(shù)據(jù)必須本地存儲于瀏覽器中。這時候 IndexDB 及其它類似的 API 就派上用場了。大體上說,一個客戶端存儲是必須的。為了不阻塞 UI 線程的渲染,這項工作必須由 Web Workers 來執(zhí)行。呃,當(dāng)使用 IndexDB的時候,可以不使用 workers 而使用其異步接口,但是之前它也含有同步接口(可能會再次引入 ),這時候就必須在 workers 中使用 IndexDB。

這里需要注意的是在現(xiàn)代瀏覽器已經(jīng)不支持同步接口了,具體可查看這里。

拼寫檢查:一個基本的拼寫檢測器是這樣工作的-程序會讀取一個包含拼寫正確的單詞列表的字典文件。字典會被解析成一個搜索樹以加快實際的文本搜索。當(dāng)檢查器檢查一個單詞的時候,程序會在預(yù)構(gòu)建搜索樹中進行檢索。如果在樹中沒有檢索到,則會通過提供替代的字符為用戶提供替代的拼寫并檢測單詞是否是有效-是否是用戶需要的單詞。這個檢索過程中的所有工作都可以交由 Web Worker 來完成,這樣用戶就只需輸入單詞和語句而不會阻塞 UI,與此同時 worker 會處理所有的搜索和服務(wù)建議。

在 SessionStack 中對于我們來說性能和可靠性是至關(guān)重要的。之所以這么重要的原因是一旦把 SessionStack 整合進網(wǎng)絡(luò)應(yīng)用,它就會開始收集從 DOM 變化,用戶交互到網(wǎng)絡(luò)請求,未處理異常和調(diào)試信息的所有一切信息。所有的數(shù)據(jù)都是即時傳輸?shù)轿覀兊姆?wù)器的,這樣就允許你以視頻的方式重放網(wǎng)絡(luò)應(yīng)用中的所有問題以及觀察用戶端產(chǎn)生的一切問題。所有的一切都只會給你的程序帶來極小的延遲且沒有任何的性能開銷。

這就是為什么我們使用 Web Workers 來處理監(jiān)視庫和播放器的邏輯的原因,因為 Web Workers 會幫我們處理諸如使用哈希來驗證數(shù)據(jù)完整性,渲染等 CPU 密集型的任務(wù)。

在這個網(wǎng)絡(luò)技術(shù)日新月異的時代,我們更加努力地保證 SessionStack 輕巧且不會給用戶程序帶來任何性能影響。

擴展

實際工作過程會遇到用戶需要通過解析遠程圖片來獲得圖片 base64 的案例,那么這時候,如果圖片非常大,就會造成 canvas 的 toDataURL 操作相當(dāng)?shù)暮臅r,從而阻塞頁面的渲染。

所以解決思路即把這里的處理圖片的操作交由 worker 來處理。以下貼出主要的代碼:




  
  Canvas to base64


  

以上是通過 canvas 來獲取圖片數(shù)據(jù),那么是否有其它方法呢?肯定有的啦,動下腦筋吧少年。

本系列持續(xù)更新中,Github 地址請查閱這里。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/95131.html

相關(guān)文章

  • JavaScript工作原理(七):Web Workers的構(gòu)建快和5使用場景

    摘要:異步編程通過在事件循環(huán)中調(diào)度要稍后執(zhí)行的部分代碼來使應(yīng)用程序能夠響應(yīng),從而允許首先執(zhí)行渲染。工作人員將通過定義的消息處理程序處理該消息。的應(yīng)用場景到目前為止,我們列出了的優(yōu)勢和局限性。 這一次我們將分拆Web Workers:我們將提供一個概述,討論不同類型的workers,他們的組成部分如何共同發(fā)揮作用,以及他們在不同情況下提供的優(yōu)勢和局限性。最后,我們將提供5個用例,其中Web W...

    sevi_stuo 評論0 收藏0
  • JavaScript 工作原理之八-Service Workers,生命周期使用場景

    摘要:生命周期的生命周期和網(wǎng)頁完全不相關(guān)。意即會作用于整個源地址上。激活安裝完之后下一步即激活。同時檢查響應(yīng)類型是否為,即檢查請求是否同域。創(chuàng)建新的的過程將會啟動,然后觸發(fā)事件??梢岳媒俪志W(wǎng)絡(luò)連接和偽造響應(yīng)數(shù)據(jù)。 原文請查閱這里,略有刪減,本文采用知識共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工...

    oysun 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<