淺談webWorker

来源:http://www.cnblogs.com/giggle/archive/2016/04/03/5350288.html
-Advertisement-
Play Games

在"setTimeout那些事兒"中,說到JavaScript是單線程。也就是同一時間只能做同一事情。 也好理解,作為瀏覽器腳本語言,如果JavaScript不是單線程,那麼就有點棘手了。比如,與用戶交互或者對DOM進行操作時,在一個線程上修改某個DOM,另外的線程刪除DOM,這時瀏覽器該如何抉擇呢 ...


webWorker之初體驗

"setTimeout那些事兒"中,說到JavaScript是單線程。也就是同一時間只能做同一事情。

也好理解,作為瀏覽器腳本語言,如果JavaScript不是單線程,那麼就有點棘手了。比如,與用戶交互或者對DOM進行操作時,在一個線程上修改某個DOM,另外的線程刪除DOM,這時瀏覽器該如何抉擇呢?

所以,JavaScript是單線程也是有背景的。

如下:

<!DOCTYPE html>
    <head>
        <title>singleThread</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
            //添加到任務隊列中,待同步任務所處的‘執行棧’執行完畢,1秒後執行任務隊列中的這個匿名函數
            setTimeout(function(){
                console.log('come on');
            },1000);
            //只要不關閉該alert,‘執行棧’就沒結束,從而也就不會進入到任務隊列中
            alert('waiting');
        </script>
    </body>
</html>

但,HTML5引入了一個工作線程(webWorker)的概念。它允許開發人員編寫能夠長時間運行而不被用戶所中斷的後臺程式,去執行事務或者邏輯,並同時保證頁面對用戶的響應。

簡而言之,就是允許JavaScript創建多個線程,但是子線程完全受主線程式控制制,且不得操作DOM

從而,可以用webWorker來處理一些比較耗時的計算。

如下,主頁面:

<!DOCTYPE html>
    <head>
        <title>worker</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <script>
            function init(){
                //創建一個Worker對象,並向它傳遞將在新線程中執行的腳本url
                var worker = new Worker('worker.js');
                //接收worker傳遞過來的數據
                worker.onmessage = function(event){
                    document.getElementById('result').innerHTML+=event.data+"<br/>" ;
                };
            };
        </script>
    </head>
    <body onload = "init()">
        <div id="result"></div>
    </body>
</html>

下麵是worker.js的內容:

var i = 0;
function timedCount(){
    for(var j = 0, sum = 0; j < 100; j++){
        for(var i = 0; i < 100000000; i++){
            sum+=i;
        };
    };
    //將得到的sum發送回主線程
    postMessage(sum);
};
//將執行timedCount前的時間,通過postMessage發送回主線程
postMessage('Before computing, '+new Date());
timedCount();
//結束timedCount後,將結束時間發送回主線程
postMessage('After computing, ' +new Date());

上面代碼執行的流程是:創建的worker對象,並用onmessage方法接收worker.js裡面postMessage傳遞過來的數據(event.data),並將數據追加到div#result中。

所以,執行上面的代碼結果如下:

 

                                                   圖一

 

待worker.js中的timedCount方法運算完後,執行postMessage操作,向主線程傳數據,得圖二。期間,並不影響主線程的運作。

 

                                                   圖二

webWorker之常用API

接下來,再來看看關於worker的常用API:

1、postMessage(data)

子線程與主線程之間互相通信使用方法,傳遞的data為任意值。

//worker = new Worker('url');
//worker.postMessage傳遞給子線程數據,對象
worker.postMessage({first:1,second:2});

//子線程中也可以使用postMessage,如傳遞字元串
postMessage(‘test’);

2、terminate()

主線程中終止worker,此後無法再利用其進行消息傳遞。註意:一旦terminate後,無法重新啟用,只能另外創建。

//worker = new Worker('url');
worker.terminate();

如,主頁面:

<!DOCTYPE html>
    <head>
        <title>worker</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <script>
            function init(){
                var worker = new Worker('worker.js');
                //每隔100毫秒,向子線程傳遞{name: 'monkey'}信息
                setInterval(function(){
                    worker.postMessage({name: 'monkey'});
                },100);
                //當主線程worker收到來自子線程的消息後,觸發message事件
                worker.onmessage = function(event){
                    document.getElementById('result').innerHTML+=event.data+"<br/>" ;
                    //主線程使用terminate方法中斷與子線程來往,在瀏覽器中只能顯示一次event.data
                    worker.terminate();
                };
            };
        </script>
    </head>
    <body onload = "init()">
        <div id="result"></div>
    </body>
</html>

子線程worker.js代碼:

//當主線程發來信息後,觸發該message事件
onmessage = function(event){
    //向主線程發送event.data.name信息
    postMessage(event.data.name);
};

3、message

當有消息發送時,觸發該事件。且,消息發送是雙向的,消息內容可通過data來獲取。

message使用,可見terminate中的demo

4、error

出錯處理。且錯誤消息可以通過e.message來獲取。

如下:

//worker = new Worker('url');
worker.onerror = function(e){
    //列印出錯消息
    console.log(e.message);
    //中斷與子線程的聯繫
    worker.terminate();
}

另:worker線程從上到下同步運行它的代碼,然後進入非同步階段來對事件及計時器響應,如果worker註冊了message事件處理程式,只要其有可能觸發,worker就一直在記憶體中,不會退出,所以通信完畢後得手動在主線程中terminate或者子線程中close掉但如果worker沒有監聽消息,那麼當所有任務執行完畢(包括計數器)後,他就會退出。

worker上下文

先看下麵這段代碼:

主頁面:

<!DOCTYPE html>
    <head>
        <title>worker</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <script>
            function init(){
                var worker = new Worker('worker.js');
                //接收消息事件
                worker.onmessage = function(event){
                    console.log(event.data);
                };
                //錯誤信息事件
                worker.onerror = function(e){
                    console.log('erro: ' + e.message);
                    //終止線程
                    worker.terminate();
                };
            };
        </script>
    </head>
    <body onload = "init()">
        
    </body>
</html>

worker.js

//window對象的alert方法
alert(1);
onmessage = function(event){
    //向主線程發送event.data.name信息
    postMessage(event.data.name);
};

執行上面代碼結果:

為什麼會這樣呢?原因是alert為window對象的方法,所以會報錯undefined。

worker.js執行的上下文,與主頁面html執行時的上下文並不相同,最頂層的對象並不是window,woker.js執行的全局上下文,是個叫做WorkerGlobalScope的東東,所以無法訪問window、與window相關的DOM API,但是可以與setTimeout、setInterval等協作。
WorkerGlobalScope作用域下的常用屬性、方法如下:

1、self

  我們可以使用 WorkerGlobalScope 的 self 屬性來或者這個對象本身的引用

2、location

  location 屬性返回當線程被創建出來的時候與之關聯的 WorkerLocation 對象,它表示用於初始化這個工作線程的腳步資源的絕對 URL,即使頁面被多次重定向後,這個 URL 資源位置也不會改變。

3、close

  關閉當前線程,與terminate作用類似

4、importScripts

  我們可以通過importScripts()方法通過url在worker中載入庫函數

5、XMLHttpRequest

  有了它,才能發出Ajax請求

6、setTimeout/setInterval以及addEventListener/postMessage

關於worker

我們可以做什麼:

  1.可以載入一個JS進行大量的複雜計算而不掛起主進程,並通過postMessage,onmessage進行通信

  2.可以在worker中通過importScripts(url)載入另外的腳本文件

  3.可以使用 setTimeout(), clearTimeout(), setInterval(), and clearInterval()

  4.可以使用XMLHttpRequest來發送請求

  5.可以訪問navigator的部分屬性

局限性:

  1.不能跨域載入JS

  2.worker內代碼不能訪問DOM

  3.各個瀏覽器對Worker的實現不大一致,例如FF里允許worker中創建新的worker,而Chrome中就不行

  4.IE這個新特性


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 遍歷List的多種方式 在講如何線程安全地遍歷List之前,先看看通常我們遍歷一個List會採用哪些方式。 方式一: 方式二: 方式三: 方式四(Java 8): 方式五(Java 8 Lambda): 首先,方式一的遍歷方法是一種非常不建議使用的方式,特別是對於LinkedList。LinkedL ...
  • 輸出:用print()在括弧中加上字元串,就可以向屏幕上輸出指定的文字。比如輸出'hello, world',用代碼實現如下>>>print('hello,world') 也可以是多個字元串,中間用逗號鏈接‘;代碼實現如下>>>print('The quick bronw fox','jumps o ...
  • 原文鏈接:http://www.orlion.ga/207/ 一、代理模式 代理模式是經常用到的設計模式,代理模式是給指定對象提供代理對象。由代理對象來控制具體對象的引用。 代理模式涉及到的角色: 抽象主題角色:聲明瞭代理主題和真實主題的公共介面,使任何需要真實主題的地方都能用代理主題代替。 代理主 ...
  • 剛拜讀 @Learning hard 的 [Asp.net 開發系列之SignalR篇]專題一:Asp.net SignalR快速入門 跟著博文一步步操作,這是新人的學習方式 然而筆者的開發環境和 @Learning hard 的有所不同,導致出現了一些小的問題! 筆者環境 VS2013 + .ne ...
  • × 目錄 [1]變形原點 [2]變形函數 [3]多值 前面的話 CSS變形transform是一些效果的集合,主要是移動、旋轉、縮放和傾斜這四種基本操作,還可以通過設置matrix矩陣來實現更複雜的效果。變形transform可以實現2D和3D兩種效果。2D變形涉及的屬性主要有transform變形 ...
  • 同源策略 在瀏覽器的安全策略中“同源策略”非常如雷貫耳,說的是協議、功能變數名稱、埠相同則視為同源,功能變數名稱也可換成IP地址,不同源的頁面腳本不能獲取對方的數據。 要是想使用XMLHttpRequest或者常規的AJAX請求獲取另一個站點的數據,瀏覽器會告訴你“XXXX is not allowed by A ...
  • 之前說要整理這塊內容,分享給大家,工作原因,直到現在,趕上清明宅在家裡,趕緊整理出來與大家分享。 精靈圖(CSS sprite) 所謂精靈圖,其實就是把幾張圖拼成一張圖。從而在低併發的瀏覽器上達到快速傳輸並呈現內容的目的(減少請求)。 在用到這些圖片的時候,需要引用整張圖片然後設定坐標到需要的那張小 ...
  • 轉自:http://kb.cnblogs.com/page/534571/ 一直都聽說DOM很慢,要儘量少的去操作DOM,於是就想進一步去探究下為什麼大家都會這樣說,在網上學習了一些資料,這邊整理出來。 首先,DOM對象本身也是一個js對象,所以嚴格來說,並不是操作這個對象慢,而是說操作了這個對象後 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...