我的認爲HTML5最吸引人的兩大功能, web socket 和 worker爲構建高效能的web應用提供了新的參考方案。javascript
大致來講,web socket提供更高效的傳輸協議,web worker提供多線程提升web應用計算效率。最近項目有用到,對應兩個問題的解決,目前運行效果來看仍是很不錯。html
這裏主要是總結這兩個技術的基礎原理,和經常使用API。備忘,也列舉關鍵掌握點,入門和基礎使用足以。java
websocket是一種協議,本質上和http,tcp同樣。協議是用來講明數據是如何傳輸的。它的url前綴是ws:// 或者wss://,後者是加密的。客戶端和服務端進行websocket交互的方式也有人理解爲「HTTP握手+TCP數據傳輸」的方式。web
HTTP握手+TCP數據傳輸:跨域
瀏覽器(支持Websocket的瀏覽器)像HTTP同樣,發起一個請求,而後等待服務端的響應;瀏覽器
服務器返回握手響應,告訴瀏覽器請將後續的數據按照websocket制定的數據格式傳過來;服務器
瀏覽器和服務器的socket鏈接不中斷,此時這個鏈接和http不一樣的是它是雙工的了;websocket
瀏覽器和服務器有任何須要傳遞的數據的時候使用這個長鏈接進行數據傳遞多線程
這裏說它是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(); })
當在 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");