轉載:https://my.oschina.net/u/2274721/blog/419772
個人認爲HTML5最吸引人的兩大功能, web socket 和 worker爲構建高效能的web應用提供了新的參考方案。
大體來說,web socket提供更高效的傳輸協議,web worker提供多線程提高web應用計算效率。最近項目有用到,對應兩個問題的解決,目前運行效果來看還是很不錯。
這裏主要是總結這兩個技術的基礎原理,和常用API。備忘,也列舉關鍵掌握點,入門和基礎使用足以。
Web Socket
websocket是一種協議,本質上和http,tcp一樣。協議是用來說明數據是如何傳輸的。它的url前綴是ws:// 或者wss://,後者是加密的。客戶端和服務端進行websocket交互的方式也有人理解爲“HTTP握手+TCP數據傳輸”的方式。
HTTP握手+TCP數據傳輸:
瀏覽器(支持Websocket的瀏覽器)像HTTP一樣,發起一個請求,然後等待服務端的響應;
服務器返回握手響應,告訴瀏覽器請將後續的數據按照websocket制定的數據格式傳過來;
瀏覽器和服務器的socket連接不中斷,此時這個連接和http不同的是它是雙工的了;
瀏覽器和服務器有任何需要傳遞的數據的時候使用這個長連接進行數據傳遞
這裏說它是HTTP握手,是因爲瀏覽器和服務器在建立長連接的握手過程是按照HTTP1.1的協議發送的,有Request,Request Header, Response, Response Header。但是不同的是Header裏面的字段是有特定含義的。
說它是TCP傳輸,主要體現在建立長連接後,瀏覽器是可以給服務器發送數據,服務器也可以給瀏覽器發送請求的。當然它的數據格式並不是自己定義的,是在要傳輸的數據外層有ws協議規定的外層包的。
數據傳輸過程
websocket的數據傳輸是frame形式傳輸的,比如會將一條消息分爲幾個frame,按照先後順序傳輸出去。這樣做會有幾個好處:
大數據的傳輸可以分片傳輸,不用考慮到數據大小導致的長度標誌位不足夠的情況。
和http的chunk一樣,可以邊生成數據邊傳遞消息,即提高傳輸效率。
客戶端API
下面是在客戶端使用websocket的API,語法就是基礎的javascript,非常簡單。只有服務端的API,有多種web框架支持,比如play,可以自行搜索。
var socket;
$("#connect").click(function(event){
socket = new WebSocket("ws://127.0.0.1:8999/getLog");
socket.onopen = function(){
console.log("Socket has been opened");
}
socket.onmessage = function(msg){
console.log("get log: " + msg.data);
}
socket.onclose = function() {
alert("Socket has been closed");
}
socket.onerror = function() {
console.log(“Web Socket Error!”);
}
});
$("#send").click(function(event){
socket.send("send from client");
});
$("#close").click(function(event){
socket.close();
})
web worker
當在 HTML 頁面中執行腳本時,頁面的狀態是不可響應的,直到腳本已完成。
而web worker 是運行在後臺的 JavaScript,獨立於其他腳本,不會影響頁面的性能。您可以繼續做任何願意做的事情:點擊、選取內容等等,而此時 web worker 在後臺運行。
除了DOM操作之外,理論上任何JS腳本任務都可放入worker中執行;語法上的限制,則是不能跨域訪問JS。worker常用於需要消耗大量時間和CPU資源的複雜計算,以換來前臺用戶操作的友好型;換句話說,從用戶體驗上看,提高了服務性能。
API
worker的主線程和子線程間通過postMessage()來發送消息,通過向 web worker 添加一個 “onmessage” 事件監聽器來獲取接受到的消息。
當我們創建 web worker 對象後,它會繼續監聽消息(即使在外部腳本完成之後)直到其被終止爲止。如需終止 web worker,並釋放瀏覽器/計算機資源,使用 terminate() 方法即可。
var worker =new Worker("worker_job.js"); //創建一個Worker對象並向它傳遞將在新線程中執行的腳本的URL
worker.postMessage("hello world"); //向worker發送數據
worker.onmessage =function(evt){ //接收worker傳過來的數據函數
console.log(evt.data); //輸出worker發送來的數據
}
也可以通過添加事件監聽器來處理message,在worker內部通過self.函數來和主線程通信:
self.addEventListener('message', function(e) {
var data = e.data;
if(data == 'init')
init();
else
...
}, false);
self.postMessage("hello worker");