HTML5新特性-多線程(Worker SharedWorker)

来源:http://www.cnblogs.com/floor/archive/2017/04/16/6720261.html
-Advertisement-
Play Games

There is no doubt that JavaScript是沒有多線程之說的,他只能一件事一件事的做,做完一件事再做下一件事,假如你的js要花一段比較長的時間做一件事的話,那麼瀏覽器將會卡頓一段時間,不對用戶的操作產生響應,這可咋辦呢?謝天謝地,HTML5為我們提供了實現多線程的機制,這麼好... ...


  There is no doubt that JavaScript是沒有多線程之說的,他只能一件事一件事的做,做完一件事再做下一件事,假如你的js要花一段比較長的時間做一件事的話,那麼瀏覽器將會卡頓一段時間,不對用戶的操作產生響應,這可咋辦呢?謝天謝地,HTML5為我們提供了實現多線程的機制,這麼好的東西,想必你早就再用了,不過沒關係啊,咱們一塊兒複習一下咯!

一、Worker類

  1、方法介紹

  (1)構造函數 new Worker(arg)  :參數表示你的線程要執行的代碼所在的js文件,例如‘myworker.js’,構造函數當然是返回一個Worker類的實例

  (2)worker.postMessage(message):這個方法表示從主線程向子線程發送消息或者子線程向主線程發送消息,message一般是一個字元串,也可以將一個js對象轉成字元串發過去

  (3)worker上還有一個message事件,當有人向這個worker實例發送消息時,該事件被觸發,我們可以從他的事件對象的data屬性中獲得post過來的值

  可以看到Woker類的API是相當簡潔的,只有兩個最常用的方法,一個事件,下麵我們來通過實際的例子看看。

  

//main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>main</title>
</head>
<body>
    <div id="out"></div>
    <input type="text" name="" id="txt">
    <button id="btn">發送</button>
    <script type="text/javascript">
        var out = document.getElementById("out");
        var btn = document.getElementById("btn");
        var txt = document.getElementById("txt");
        var worker = new Worker("thread1.js");
        btn.addEventListener("click",function(){
            var postData = txt.value;
            worker.postMessage(postData);
        },false);
        worker.addEventListener('message',function(e){
            out.innerText = e.data;
        },false);
    </script>
</body>
</html>
//thread1.js

onmessage = function(event){
    var res = event.data+"帥氣!";
    postMessage(res);
}

  當我在文本框輸入“大~熊”點擊發送按鈕就會出現如下效果

  

  簡單分析分析,我在主線程由thead1.js創建了一個Worker的實例worker,當點擊按鈕時會調用他的postMessage方法,將文本框中的內容發送到thread1.js,我們的thread1.js怎麼做的呢?是這樣,他偵聽message事件,主線程發送消息過來就觸發這個事件,執行回調函數,回調函數從事件對象取得發送來的值,然後將這個值加上“帥氣!”,然後在發送回去。主線程呢也偵聽了worker的message事件,所以有消息過去時會觸發,將消息內容顯示在div中,如此就看到了上面的效果。

  或許你會將這有什麼用呢?這裡確實沒什麼用,這裡我們大可以在主線程還總完成加“帥氣!”的操作,因為他的複雜度為O(1)(哈哈,最近在學演算法!),但是假如不是做這麼簡單的操作呢?這種方法的好處就是不過你的子線程做多麼複雜的工作,都不會讓主線程停下來,主線程改幹嘛還幹嘛,等到子線程把數據處理好了他直接拿過來就好了。

  陸老師將可以在子線程中在調用new Worker()創建新的子線程,我發現這樣是不可以的,會報undefined錯誤,也就是說子線程中是不能調用Worker構造函數的,一開始以為是自己錯了,後來查閱了官方文檔,發現也沒有相關的描述。

  下麵看一個在主線程調用多個子線程的例子:

//main.html
<!
DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>main</title> </head> <body> <div id="out"></div> <input type="text" name="" id="txt"> <button id="btn">發送</button> <script type="text/javascript"> var out = document.getElementById("out"); var btn = document.getElementById("btn"); var txt = document.getElementById("txt"); var worker1 = new Worker("thread1.js"); var worker2 = new Worker("thread2.js"); btn.addEventListener("click",function(){ var postData = txt.value; worker1.postMessage(postData); },false); worker1.addEventListener('message',function(e){ worker2.postMessage(e.data); },false); worker2.addEventListener('message',function(e){ out.innerText = e.data; },false); </script> </body> </html>

 

//thread1.js

onmessage = function(event){
    var res = event.data+"帥氣!";
        postMessage(res);    
}

 

//thread2.js
onmessage = function(event){
    var res = event.data+"沒騙你喲!";
    postMessage(res);
    close();
}

  主線程要完成一個任務需要兩個線程,它創建了兩個線程worker1,2,先向worker1請求,得到返回的數據後,再請求worker2,同時將worker1處理之後的數據交給worder2處理,然後拿到最終結果,顯示在頁面上。

  在子線程中可以引入其他的js文件然後調用,比如下邊這個例子。

  

//main.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>main</title>
</head>
<body>
    <div id="out"></div>
    <input type="text" name="" id="txt">
    <button id="btn">發送</button>
    <script type="text/javascript">

        var out = document.getElementById("out");
        var btn = document.getElementById("btn");
        var txt = document.getElementById("txt");
        var worker1 = new Worker("thread1.js");
        btn.addEventListener("click",function(){
            var postData = txt.value;
            worker1.postMessage(postData);
        },false);
        worker1.addEventListener('message',function(e){
            out.innerText = e.data;
            
        },false);
    </script>
</body>
</html>
//thread1.js
importScripts('tools.js')
onmessage = function(event){
    var res = handler(event.data);
        postMessage(res);    
}
//tools.js
function handler(data){
    return data+"加油加油!"
}

  可以看到我們的thread1.js並沒有一個叫做tools.js的文件,但是它通過importScripts()導入了一個js文件,然後就可以調用裡邊暴露出來的方法了。

二、SharedWorker類

  SharedWorker的實質在於share,不同的線程可以共用一個線程,他們的數據也是共用的。

  直接用例子來探討。

  使用方法一:

//main.html
<!DOCTYPE HTML>
<head>
    <title>Shared workers: demo 1</title>
</head>
<body>
    <div id="log"></div>

<script>
  var worker = new SharedWorker('shared.js');
  var log = document.getElementById('log');
  worker.port.onmessage = function(e) { // note: not worker.onmessage!
    log.textContent += '\n' + e.data;
  }
</script>
</body>
</html>
//shared.js

onconnect = function(e) {
  var port = e.ports[0];
  port.postMessage('Hello World!');
}

  這是從w3c拿得一個例子,下麵先看第二種方法,再做分析

  

<!DOCTYPE HTML>
<html>
<head>
    <title>Shared workers: demo 2</title>
</head>
<body>
<div id="log"></div>
<script>
  var worker = new SharedWorker('shared.js');
  var log = document.getElementById('log');
  worker.port.addEventListener('message', function(e) {
    log.textContent += '\n' + e.data;
  }, false);
  worker.port.start(); // note: need this when using addEventListener
  worker.port.postMessage('ping');
</script>
</body>
</html>  
//shared
onconnect = function(e) {
  var port = e.ports[0];
  port.postMessage('Hello World!');
  port.onmessage = function(e) {
    port.postMessage('pong'); // not e.ports[0].postMessage!
    // e.target.postMessage('pong'); would work also
  }
}

 

  第一種方法中是使用事件句柄的方式將聽message事件,不需要調用worker.port.start(),第二種方法是通過addEventListener()方法監聽message事件,需要worker.port.start()方法激活埠。他們不同於worker,當有人和他通信時觸發connect事件,然後他的message事件是綁定在messagePort對象上的,不想worker那樣,你可以回頭看看worker是怎麼做的。

  那麼sharedWorker是怎麼共用數據的呢?請看下麵的例子。

  

//main1 和main2都是這樣

<!DOCTYPE HTML>
<html>
<head>
    <title>Shared workers: demo 2</title>
</head>
<body>
<div id="log"></div>
<input type="text" name="" id="txt">
<button id="get">get</button>
<button id="set">set</button>
<script>
  var worker = new SharedWorker('shared.js');
  var get = document.getElementById('get');
  var set = document.getElementById('set');
  var txt = document.getElementById('txt');
  var log = document.getElementById('log');

  worker.port.addEventListener('message', function(e) {
    log.innerText = e.data;
  }, false);
  worker.port.start(); // note: need this when using addEventListener

  set.addEventListener('click',function(e){
      worker.port.postMessage(txt.value);
  },false);

  get.addEventListener('click',function(e){
      worker.port.postMessage('get');
  },false);
</script>
</body>
</html>
//shared
var data;
onconnect = function(e) {
  var port = e.ports[0];
  port.onmessage = function(e) {
    
    if(e.data=='get'){
        port.postMessage(data);
    }else{
        data=e.data;
    }
  }
}

  這裡分析一波,我們在main1.html的文本框輸入數據,點擊set,然後在main2.html中點擊get法現能夠獲取到我們在main1.html中設置的數據,這說明我們的sharedWorker事實上是單例的,就像java中的static類一樣,不管new多少個,實際上只有一個,這樣我們的不同線程就可以共用到sharedWorker中的數據了。這裡把圖給上,記得有篇文章沒給圖,然後有人給我建議了,問能不能給圖。

  

  最後來小結一下,worker和sharedWorker沒有什麼懸糊的,就是把台前的工作搬到幕後去做,不打斷台前的工作。正所謂臺上十分鐘,臺下十年功,如果你把臺下的十年供放到臺上做,觀眾的唾沫星子早就把你淹死了,所以說那些費事費力的工作還是放到臺下去,臺上只用展示你最好的一面的好了,十分鐘足以!

  最最後,如果您覺得我的文章對您有所幫助的話,不妨關註一下我,您的支持是對我最大的鼓勵。

  參考:

  html5與css3權威指南上冊(陸)

  https://www.w3.org/TR/2015/WD-workers-20150924/#dedicated-workers-and-the-dedicatedworkerglobalscope-interface


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

-Advertisement-
Play Games
更多相關文章
  • 設計模式是面向對象編程的基礎,是用於指導程式設計。在實際項目開發過程中,並不是一味將設計模式進行套用,也不是功能設計時大量引入設計模式。應該根據具體需求和要求應用適合的設計模式。設計模式是一個老話題了,因為最近在設計“網關API”組件(後續介紹),採用“責任鏈設計模式”進行設計,所以先進行回顧記錄。 ...
  • 購物車主要作用在於:1、和傳統賣場類似,方便用戶一次選擇多件商品去結算。2、充當臨時收藏夾的功能。3、對於商家來說,購物車是向用戶推銷的最佳場所之一。 早期 ERP拆分 業務服務化拆分 WCS拆分 購物車功能模塊概況 層級設計 群集設計 雲購物車從應用層 面上設計了三個—— 交互層、業務... ...
  • 1 概念定義 1 概念定義 1.1 定義 確保一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。 1.2 類型 創建類模式 1.3 難點 1)多個虛擬機 當系統中的單例類被拷貝運行在多個虛擬機下的時候,在每一個虛擬機下都可以創建一 個實例對象。在使用了 EJB、JINI、RMI 技術的分佈 ...
  • 項目下載地址:http://download.csdn.net/detail/aqsunkai/9805821 (一)yml配置文件: pom.xml加入依賴: 在application.yml文件中加上: 使用一個java類獲取yml文件的內容: 通過依賴註入就可以獲取該對象: 方法內獲取值: ( ...
  • 第一次寫博客,有點小激動。由於我的興趣方向是web前端,所以就給自己設計了個頁面。 這個頁面的主要特點就是磨砂效果,還有背景固定效果。靜止不動首先想到的就是position: fixed,只要將背景圖填滿全屏,再設置固定定位就可以了。不過要註意不能把#home當做固定背景,否則子元素也會固定,滾動條 ...
  • 前言:這是筆者學習之後自己的理解與整理。如果有錯誤或者疑問的地方,請大家指正,我會持續更新! innerHTML 在讀模式下,返回與調用元素的所有子節點(包括元素、註釋和文本節點)對應的 HTML 標記; 在寫模式下,innerHTML 會根據指定的值創建新的 DOM 樹,然後用這個 DOM 樹完全 ...
  • 最近由於項目的需要,做了一個基於JQuery的表格分頁插件封裝,部分源碼來源百度,經由自己封裝完成。 下麵是具體代碼和說明,僅供參考。第一步可以先將我的HTML,CSS,JS這三部分的代碼創建好後先運行看看,下圖是文件目錄展示。 html CSS js 好了,到了這裡如果你完成了創建並且運行可以看到 ...
  • First First Second Second ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...