WebSocket&webWorkers

WebSocket是HTML5開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議。


實現背景

WebSocket協議之前,雙工通信是通過多個http鏈接來實現,這導致了效率低下。
長久以來,創建實現客戶端和用戶端之間雙工通訊的web app都會造成HTTP輪詢的濫用: 客戶端向主機不斷髮送不同的HTTP呼叫來進行詢問。
這會導致一系列的問題:
1.服務器被迫爲每個客戶端使用許多不同的底層TCP連接:一個用於向客戶端發送信息,其它用於接收每個傳入消息。
2.有線協議有很高的開銷,每一個客戶端和服務器之間都有HTTP頭。
3.客戶端腳本被迫維護從傳出連接到傳入連接的映射來追蹤回覆
實現原理

在實現websocket連線過程中,需要通過瀏覽器發出websocket連線請求,然後服務器發出迴應,這個過程通常稱爲“握手” 。在 WebSocket API,瀏覽器和服務器只需要做一個握手的動作,然後,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。在此WebSocket 協議中,爲我們實現即時服務帶來了兩大好處:
1. Header
互相溝通的Header是很小的-大概只有 2 Bytes
2. Server Push
服務器的推送,服務器不再被動的接收到瀏覽器的請求之後才返回數據,而是在有新數據時就主動推送給瀏覽器。


var Socket = new WebSocket(url, [protocol] );

第一個參數 url, 指定連接的 URL。第二個參數 protocol 是可選的,指定了可接受的子協議。


WebSocket 屬性

以下是 WebSocket 對象的屬性。假定我們使用了以上代碼創建了 Socket 對象:

屬性 描述
Socket.readyState

只讀屬性 readyState 表示連接狀態,可以是以下值:

  • 0 - 表示連接尚未建立。

  • 1 - 表示連接已建立,可以進行通信。

  • 2 - 表示連接正在進行關閉。

  • 3 - 表示連接已經關閉或者連接不能打開。

Socket.bufferedAmount

只讀屬性 bufferedAmount 已被 send() 放入正在隊列中等待傳輸,但是還沒有發出的 UTF-8 文本字節數。


WebSocket 事件

以下是 WebSocket 對象的相關事件。假定我們使用了以上代碼創建了 Socket 對象:

事件 事件處理程序 描述
open Socket.onopen 連接建立時觸發
message Socket.onmessage 客戶端接收服務端數據時觸發
error Socket.onerror 通信發生錯誤時觸發
close Socket.onclose 連接關閉時觸發

WebSocket 方法

以下是 WebSocket 對象的相關方法。假定我們使用了以上代碼創建了 Socket 對象:

方法 描述
Socket.send()

使用連接發送數據

Socket.close()

關閉連接


websocket的應用場景:

決定手頭的工作是否需要使用WebSocket技術的方法很簡單:

  • 你的應用提供多個用戶相互交流嗎?
  • 你的應用是展示服務器端經常變動的數據嗎?

如果你的回答是肯定的,那麼請考慮使用WebSocket。如果你仍然不確定,並想要更多的靈感,這有一些殺手鐗的案例。

 

1.社交訂閱

對社交類的應用的一個裨益之處就是能夠即時的知道你的朋友正在做什麼。雖然聽起來有點可怕,但是我們都喜歡這樣做。你不會想要在數分鐘之後才能知道一個家庭成員在餡餅製作大賽獲勝或者一個朋友訂婚的消息。你是在線的,所以你的訂閱的更新應該是實時的。

2.多玩家遊戲

網絡正在迅速轉變爲遊戲平臺。在不使用插件(我指的是Flash)的情況下,網絡開發者現在可以在瀏覽器中實現和體驗高性能的遊戲。無論你是在處理DOM元素、CSS動畫,HTML5的canvas或者嘗試使用WebGL,玩家之間的互動效率是至關重要的。我不想在我扣動扳機之後,我的對手卻已經移動位置。

 

3.協同編輯/編程

我們生活在分佈式開發團隊的時代。平時使用一個文檔的副本就滿足工作需求了,但是你最終需要有一個方式來合併所有的編輯副本。版本控制系統,比如Git能夠幫助處理某些文件,但是git發現一個它不能解決的衝突時,你仍然需要去跟蹤人們的修改歷史。通過一個協同解決方案,比如WebSocket,我們能夠工作在同一個文檔,從而省去所有的合併版本。這樣會很容易看出誰在編輯什麼或者你在和誰同時在修改文檔的同一部分。

4.點擊流數據

分析用戶與你網站的互動是提升你的網站的關鍵。HTTP的開銷讓我們只能優先考慮和收集最重要的數據部分。然後,經過六個月的線下分析,我們意識到我們應該收集一個不同的判斷標準——一個看起來不是那麼重要但是現在卻影響了一個關鍵的決定。與HTTP請求的開銷方式相比,使用Websocket,你可以由客戶端發送不受限制的數據。想要在除頁面加載之外跟蹤鼠標的移動?只需要通過WebSocket連接發送這些數據到服務器,並存儲在你喜歡的NoSQL數據庫中就可以了(MongoDB是適合記錄這樣的事件的)。現在你可以通過回放用戶在頁面的動作來清楚的知道發生了什麼。

 

5.股票基金報價

金融界瞬息萬變——幾乎是每毫秒都在變化。我們人類的大腦不能持續以那樣的速度處理那麼多的數據,所以我們寫了一些算法來幫我們處理這些事情。雖然你不一定是在處理高頻的交易,但是,過時的信息也只能導致損失。當你有一個顯示盤來跟蹤你感興趣的公司時,你肯定想要隨時知道他們的價值,而不是10秒前的數據。使用WebSocket可以流式更新這些數據變化而不需要等待。

6.體育實況更新

現在我們開始討論一個讓人們激情澎湃的愚蠢的東西——體育。我不是運動愛好者,但是我知道運動迷們想要什麼。當愛國者在打比賽的時候,我的妹夫將會沉浸於這場比賽中而不能自拔。那是一種瘋狂癡迷的狀態,完全發自內心的。我雖然不理解這個,但是我敬佩他們與運動之間的這種強烈的聯繫,所以,最後我能做的就是給他的體驗中降低延遲。如果你在你的網站應用中包含了體育新聞,WebSocket能夠助力你的用戶獲得實時的更新。

 
7.多媒體聊天

視頻會議並不能代替和真人相見,但當你不能在同一個屋子裏見到你談話的對象時,視頻會議是個不錯的選擇。儘管視頻會議私有化做的“不錯”,但其使用還是很繁瑣。我可是開放式網絡的粉絲,所以用WebSockets getUserMedia API和html5音視頻元素明顯是個不錯的選擇。WebRTC的出現順理成章的成爲我剛纔概括的組合體,它看起來很有希望,但其缺乏目前瀏覽器的支持,所以就取消了它成爲候選人的資格。

 
8.基於位置的應用

越來越多的開發者借用移動設備的GPS功能來實現他們基於位置的網絡應用。如果你一直記錄用戶的位置(比如運行應用來記錄運動軌跡),你可以收集到更加細緻化的數據。如果你想實時的更新網絡數據儀表盤(可以說是一個監視運動員的教練),HTTP協議顯得有些笨拙。借用WebSocket TCP鏈接可以讓數據飛起來。

9.在線教育

上學花費越來越貴了,但互聯網變得更快和更便宜。在線教育是學習的不錯方式,尤其是你可以和老師以及其他同學一起交流。很自然,WebSockets是個不錯的選擇,可以多媒體聊天、文字聊天以及其它優勢如與別人合作一起在公共數字黑板上畫畫...



一、概述

HTML5 WebSockets是HTML5中最強大的通信功能,它定義了一個全雙工通信信道,僅通過Web上的一個Socket即可進行通信。

目前實時Web應用的實現方式,大部分是圍繞輪詢和其他服務器端推送技術展開的,Comet、輪詢、長輪詢、流(streaming)解決方案,所有這些提供實時數據的方式包含有大量額外的、不必要的報頭數據,會造成傳輸延遲。最重要的是爲了在半雙工HTTP的基礎上模擬全雙工通信,目前的許多解決方案都是使用了兩個連接:一個用於下行數據流,另一個用於上行數據流。這兩個連接的保持和協作也會造成大量的資源消耗,並增加了複雜度。

WebSockets就是解決以上問題的方案。爲了建立WebSocket通信,客戶端和服務器在初始握手時,將HTTP協議升級到WebSocket協議。

 

現在WebSocket服務器有很多,還在開發中的更多。有一下幾種:

  • Kaazing WebSocket Gateway:一種基於Java的WebSocket網關。
  • mod_pywebsocket:一種基於Python的Apache HTTP服務器擴展。
  • Netty:一種包含WebSocket的Java框架。
  • node.js:一種驅動多個WebSocket服務器的服務器端JavaScript框架。
對於非原生支持WebSocket的瀏覽器來說,Kazzing的WebSocket網關包含了完整的客戶端瀏覽器WebSocket模擬支持。

二、HTML5 WebSockets API

1、瀏覽器支持情況檢測

檢測瀏覽器支持情況代碼  收藏代碼
  1. function loadDemo() {  
  2.     if (window.WebSocket) {  
  3.         //supported  
  4.     } else {  
  5.         // not supported  
  6.     }  
  7. }  

2、WebSocket對象的創建和服務器連接

要連接通信端點,只需要創建一個新的WebSocket實例,並提供希望連接的對端URL。ws://和wss://前綴分別表示WebSocket連接和安全的WebSocket連接。

Js代碼  收藏代碼
  1. url = "ws://localhost:8080/echo";  
  2. w = new WebSocket(url);  

 

建立WebSocket連接時,可以列出Web應用能夠使用的協議。WebSocket構造函數的第二個參數既可以是字符串,也可以是字符串組。

Js代碼  收藏代碼
  1. w = new WebSocket(url, ["proto1""proto2"]);  

假設proto1和proto2是定義明確、可能已註冊且標準化的協議名稱,它們能夠同時爲客戶端和服務器端所理解。服務器會從列表中選擇首選協議。

Js代碼  收藏代碼
  1. onopen = function(e) {  
  2.     //確定服務器選擇的協議  
  3.     log(e.target.protocol);  
  4. }  

 

3、添加事件監聽器

WebSocket編程遵循異步編程模型;打開socket後,只需等待事件發生,而不需要主動向服務器輪詢,所以需要在WebSocket對象中添加回調函數來監聽事件。

WebSocket對象有三個事件:open、close和message。

Js代碼  收藏代碼
  1. w.onopen = function() {  
  2.     log("open");  
  3.     w.send("send message");  
  4. }  
  5. w.onmessage = function(e) {  
  6.     log(e.data);  
  7. }  
  8. w.onclose = function(e) {  
  9.     log("closed");  
  10. }  
  11. w.onerror = function(e) {  
  12.     log("error");  
  13. }  

 

4、發送消息

當socket處於打開狀態(即onopen之後,onclose之前),可以用send方法來發送消息。消息發送完,可以調用close方法來終止連接,也可以不這麼做,讓其保持打開狀態。

Js代碼  收藏代碼
  1. w.send();  

 

你可能想測算在調用Send()函數之前,有多少數據備份在發送緩衝區中。bufferAmount屬性表示已在WebSocket上發送但尚未寫入網絡的字節數。它對於調節發送速率很有用。

Js代碼  收藏代碼
  1. document.getElementById("sendButton").onclick = function() {  
  2.     if (w.bufferedAmount < bufferThreshold) {  
  3.         w.send(document.getElementById("inputMessage").value);  
  4.     }  
  5. }  

WebSocket API支持以二進制數據的形式發送Blob和ArrayBuffer實例

Js代碼  收藏代碼
  1. var a = new Uint8Array([8, 6, 7, 5, 3, 0, 9]);  
  2. w.send(a.buffer);  

 

三、例子

書中介紹了一個用Python寫的Echo服務,書中的代碼可以在http://www.apress.com/9781430238645 的“Source Code/Downloads”中下載下載。

對於JAVA開發人員Tomcat是最熟悉的,在Tomcat8中已經實現了WebSocket API 1.0。Tomcat7也會在不久實現(現在的實現不是WebSocket API 1.0)。

在這裏寫一下在Tomcat8下執行的例子。

例子由客戶端頁面和WebSocket服務程序組成,功能在Echo基礎上增加一個服務端定時發送信息的功能。

 

頁面程序 ws.html代碼  收藏代碼
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta charset="UTF-8">  
  5. <title>Test WebSocket</title>  
  6. <script type="text/javascript">  
  7.     //顯示信息  
  8.     var log = function(s) {  
  9.         if (document.readyState !== "complete") {  
  10.             log.buffer.push(s);  
  11.         } else {  
  12.             document.getElementById("output").textContent += (s + "\n");  
  13.             document.getElementById("outputdiv").scrollTop = document.getElementById("outputdiv").scrollHeight;  
  14.         }  
  15.     }  
  16.     log.buffer = [];  
  17.     //顯示連接狀態  
  18.     function setConnected(status) {  
  19.         document.getElementById("socketstatus").innerHTML = status;  
  20.     }  
  21.     var ws = null;  
  22.       
  23.     //連接  
  24.     function connect() {  
  25.         if (ws != null) {  
  26.             log("現已連接");  
  27.             return ;  
  28.         }  
  29.         url = "ws://localhost:8080/websocket/mywebsocket";  
  30.         if ('WebSocket' in window) {  
  31.             ws = new WebSocket(url);  
  32.         } else if ('MozWebSocket' in window) {  
  33.             ws = new MozWebSocket(url);  
  34.         } else {  
  35.             alert("您的瀏覽器不支持WebSocket。");  
  36.             return ;  
  37.         }  
  38.         ws.onopen = function() {  
  39.             log("open");  
  40.             setConnected("已連接");  
  41.             //設置發信息送類型爲:ArrayBuffer  
  42.             ws.binaryType = "arraybuffer";  
  43.               
  44.             //發送一個字符串和一個二進制信息  
  45.             ws.send("thank you for accepting this WebSocket request");  
  46.             var a = new Uint8Array([8675309]);  
  47.             ws.send(a.buffer);  
  48.         }  
  49.         ws.onmessage = function(e) {  
  50.             log(e.data.toString());  
  51.         }  
  52.         ws.onclose = function(e) {  
  53.             log("closed");  
  54.         }  
  55.         ws.onerror = function(e) {  
  56.             log("error");  
  57.         }  
  58.     }  
  59.       
  60.     //斷開連接  
  61.     function disconnect() {  
  62.         if (ws != null) {  
  63.             ws.close();  
  64.             ws = null;  
  65.             setConnected("已斷開");  
  66.         }  
  67.     }  
  68.       
  69.     window.onload = function() {  
  70.         connect();  
  71.         log(log.buffer.join("\n"));  
  72.         //發送頁面上輸入框的信息  
  73.         document.getElementById("sendButton").onclick = function() {  
  74.             if (ws != null) {  
  75.                 ws.send(document.getElementById("inputMessage").value);   
  76.             }  
  77.         }  
  78.         //停止心跳信息  
  79.         document.getElementById("stopButton").onclick = function() {  
  80.             if (ws != null) {  
  81.                 var a = new Uint8Array([19201516]);  
  82.                 ws.send(a.buffer);   
  83.             }  
  84.         }  
  85.     }  
  86. </script>  
  87. </head>  
  88. <body οnunlοad="disconnect();">  
  89.     <div>連接狀態:<span id="socketstatus"></span></div>  
  90.     <div>  
  91.         <input type="text" id="inputMessage" value="Hello, WebSocket!">  
  92.         <button id="sendButton">發送</button><button id="stopButton" style="margin-left:15px">停止心跳信息</button>  
  93.     </div>  
  94.     <div>  
  95.         <button id="connect" οnclick="connect();">連接</button>  
  96.         <button id="disconnect" οnclick="disconnect();">斷開</button>  
  97.     </div>  
  98.     <div style="height:300px; overflow:auto;" id="outputdiv">  
  99.         <pre id="output"></pre>  
  100.     </div>  
  101. </body>  
  102. </html>  

 

服務端程序用註解方式驅動

 

Websocket服務端程序代碼  收藏代碼
  1. package com.test.wsocket;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.ByteBuffer;  
  5. import java.util.Random;  
  6. import java.util.Timer;  
  7. import java.util.TimerTask;  
  8.   
  9. import javax.websocket.OnClose;  
  10. import javax.websocket.OnMessage;  
  11. import javax.websocket.OnOpen;  
  12. import javax.websocket.PongMessage;  
  13. import javax.websocket.Session;  
  14. import javax.websocket.server.ServerEndpoint;  
  15.   
  16. @ServerEndpoint("/mywebsocket")  
  17. public class MyWebSocket {  
  18.       
  19.     private Session session;  
  20.     private static final Random random = new Random();  
  21.     private Timer timer = null;  
  22.     //停止信息信息指令  
  23.     private static final ByteBuffer stopbuffer  = ByteBuffer.wrap(new byte[]{19201516});  
  24.       
  25.     /**  
  26.      * 打開連接時執行  
  27.      * @param session  
  28.      */  
  29.     @OnOpen  
  30.     public void start(Session session) {  
  31.         this.session = session;  
  32.         try {  
  33.             System.out.println("open");  
  34.             if (session.isOpen()) {  
  35.                 //設置心跳發送信息。每2秒發送一次信息。  
  36.                 timer = new Timer(true);  
  37.                 timer.schedule(task, 10002000);  
  38.             }  
  39.         } catch (Exception e) {  
  40.             try {  
  41.                 session.close();  
  42.             } catch (IOException e1) {}  
  43.         }  
  44.     }  
  45.   
  46.     /**  
  47.      * 接收信息時執行  
  48.      * @param session  
  49.      * @param msg 字符串信息  
  50.      * @param last  
  51.      */  
  52.     @OnMessage  
  53.     public void echoTextMessage(Session session, String msg, boolean last) {  
  54.         try {  
  55.             if (session.isOpen()) {  
  56.                 System.out.println("string:" + msg);  
  57.                 session.getBasicRemote().sendText(msg, last);  
  58.             }  
  59.         } catch (IOException e) {  
  60.             try {  
  61.                 session.close();  
  62.             } catch (IOException e1) {  
  63.                 // Ignore  
  64.             }  
  65.         }  
  66.     }  
  67.   
  68.     /**  
  69.      * 接收信息時執行  
  70.      * @param session  
  71.      * @param bb 二進制數組  
  72.      * @param last  
  73.      */  
  74.     @OnMessage  
  75.     public void echoBinaryMessage(Session session, ByteBuffer bb, boolean last) {  
  76.         try {  
  77.             if (session.isOpen()) {  
  78.                 //如果是停止心跳指令,則停止心跳信息  
  79.                 if (bb.compareTo(stopbuffer) == 0) {  
  80.                     if (timer != null) {  
  81.                         timer.cancel();  
  82.                     }  
  83.                 } else {  
  84.                     session.getBasicRemote().sendBinary(bb, last);  
  85.                 }  
  86.             }  
  87.         } catch (IOException e) {  
  88.             try {  
  89.                 session.close();  
  90.             } catch (IOException e1) {  
  91.                 // Ignore  
  92.             }  
  93.         }  
  94.     }  
  95.       
  96.     /**  
  97.      * 接收pong指令時執行。  
  98.      *  
  99.      * @param pm    Ignored.  
  100.      */  
  101.     @OnMessage  
  102.     public void echoPongMessage(PongMessage pm) {  
  103.         // 無處理  
  104.     }  
  105.       
  106.     @OnClose  
  107.     public void end(Session session) {  
  108.         try {  
  109.             System.out.println("close");  
  110.             if (timer != null) {  
  111.                 timer.cancel();  
  112.             }  
  113.         } catch(Exception e) {  
  114.         }  
  115.     }  
  116.       
  117.     /*  
  118.      * 發送心跳信息  
  119.      */  
  120.     public void sendLong(long param) {  
  121.         try {  
  122.             if (session.isOpen()) {  
  123.                 this.session.getBasicRemote().sendText(String.valueOf(param));  
  124.             }  
  125.         } catch (IOException e) {  
  126.             try {  
  127.                 this.session.close();  
  128.             } catch (IOException e1) {}  
  129.         }  
  130.     }  
  131.       
  132.     /**  
  133.      * 心跳任務。發送隨機數。  
  134.      */  
  135.     TimerTask task = new TimerTask() {  
  136.         public void run() {     
  137.             long param = random.nextInt(100);  
  138.             sendLong(param);  
  139.         }     
  140.     };  
  141.   
  142. }  

 

 

Web.xml代碼  收藏代碼
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">  
  3.   <display-name>websocket</display-name>  
  4.   <welcome-file-list>  
  5.     <welcome-file>index.html</welcome-file>  
  6.   </welcome-file-list>  
  7.     
  8.   <filter>  
  9.         <filter-name>Set Character Encoding</filter-name>  
  10.         <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>  
  11.         <init-param>  
  12.             <param-name>encoding</param-name>  
  13.             <param-value>UTF-8</param-value>  
  14.         </init-param>  
  15.         <init-param>  
  16.             <param-name>ignore</param-name>  
  17.             <param-value>true</param-value>  
  18.         </init-param>  
  19.     </filter>  
  20.       
  21.     <filter-mapping>  
  22.         <filter-name>Set Character Encoding</filter-name>  
  23.         <url-pattern>/*</url-pattern>  
  24.     </filter-mapping>  
  25. </web-app>  

 

將以上程序部署到Tomcat8下,啓動服務。


礙於原作者的代碼繁瑣,我自己在嘗試的過程中也寫了一個:

<body>
<p>詳見http://toplchx.iteye.com/blog/1929427</p>
<button>關閉連接</button>
<button>打開連接</button>
<script>
if(window.WebSocket) {
console.log("support websockets");
} else {
console.log("not support websockets");
}
// var sockets=new WebSocket("ws://mx.360island.com");
var sockets = new WebSocket("ws://echo.websocket.org", ["com.kaazing.echo",
"example.imaginary.protocol"
]);
//setinterval變量
var timeCount;


//建立時便觸發
sockets.onopen = function(e) {
if(sockets.readyState == 1) {
console.log("open");
//連接成功時, 使用連接發送數據
timeCount = setInterval(sendMessage, 2000);


}
}
// 客戶端接受服務器數據時觸發
sockets.onmessage = function(e) {
//接受數據
console.log("實時接受數據" + e.data);
}
// 通信發生錯誤時觸發
sockets.onError = function() {
console.log("error");
}
//發送數據的變量
var send_num = 0;
//發送數據函數
function sendMessage() {
console.log("發送數據" + send_num);
sockets.send(send_num);
send_num++;
}


var closeWebSockets = document.getElementsByTagName("button")[0];
//點擊按鈕關閉連接
closeWebSockets.onclick = function() {
if(sockets.readyState == 1) {
sockets.close();
clearInterval(timeCount);
console.log("已經關閉連接,當前鏈接的狀態是:"+sockets.readyState);
} else {
console.log("尚未建立連接");
}
}
var openWebSockets = document.getElementsByTagName("button")[1];
//點擊按鈕關閉連接
openWebSockets.onclick = function() {
// 只有在尚未建立連接的情況下才可以再建立連接
if(sockets.readyState == 2) {
sockets = new WebSocket("ws://echo.websocket.org", ["com.kaazing.echo",
"example.imaginary.protocol"
]);
sockets.onopen = function(e) {
if(sockets.readyState == 2) {
console.log("open");
//連接成功時, 使用連接發送數據
timeCount = setInterval(sendMessage, 2000);
}
}
} else {
console.log("已經有一個同名的鏈接處於打開狀態");
}
}


</script>
</body>


webWorker


web worker 是運行在後臺的 JavaScript,不會影響頁面的性能。

什麼是 Web Worker?

當在 HTML 頁面中執行腳本時,頁面的狀態是不可響應的,直到腳本已完成。

web worker 是運行在後臺的 JavaScript,獨立於其他腳本,不會影響頁面的性能。您可以繼續做任何願意做的事情:點擊、選取內容等等,而此時 web worker 在後臺運行。

瀏覽器支持

所有主流瀏覽器均支持 web worker,除了 Internet Explorer

使用web worker需要以下幾步:

檢測 Web Worker 支持

在創建 web worker 之前,請檢測用戶的瀏覽器是否支持它:

if(typeof(Worker)!=="undefined")
  {
  // Yes! Web worker support!
  // Some code.....
  }
else
  {
  // Sorry! No Web Worker support..
  }

創建 web worker 文件

現在,讓我們在一個外部 JavaScript 中創建我們的 web worker。

在這裏,我們創建了計數腳本。該腳本存儲於 "demo_workers.js" 文件中:

var i=0;

function timedCount()
{
i=i+1;
postMessage(i);
setTimeout("timedCount()",500);
}

timedCount();

以上代碼中重要的部分是 postMessage() 方法 - 它用於向 HTML 頁面傳回一段消息。

註釋:web worker 通常不用於如此簡單的腳本,而是用於更耗費 CPU 資源的任務。

創建 Web Worker 對象

我們已經有了 web worker 文件,現在我們需要從 HTML 頁面調用它。

下面的代碼檢測是否存在 worker,如果不存在,- 它會創建一個新的 web worker 對象,然後運行 "demo_workers.js" 中的代碼:

if(typeof(w)=="undefined")
  {
  w=new Worker("demo_workers.js");
  }

然後我們就可以從 web worker 發生和接收消息了。

向 web worker 添加一個 "onmessage" 事件監聽器:

w.onmessage=function(event){
document.getElementById("result").innerHTML=event.data;
};

當 web worker 傳遞消息時,會執行事件監聽器中的代碼。event.data 中存有來自 event.data 的數據。

終止 Web Worker

當我們創建 web worker 對象後,它會繼續監聽消息(即使在外部腳本完成之後)直到其被終止爲止。

如需終止 web worker,並釋放瀏覽器/計算機資源,請使用 terminate() 方法:

w.terminate();

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章