參考:http://www.cnblogs.com/giggle/p/5350288.html(淺談webWorker)
http://blog.csdn.net/zha_zi/article/details/41677033 HTML5 中 postMessage sendMessage 用法
Web Workers----工作線程
Html5對多線程的支持。在 HTML5 中提出了工作線程(Web Workers)的概念。用於解決頁面之間數據處理的多線程,加快數據處理。如同java中的Thread。
Web Workers 的三大主要特征: 能夠長時間運行(響應),理想的啟動性能以及理想的內存消耗。
Web Workers 允許開發人員編寫能夠長時間運行而不被用戶所中斷的后台程序,去執行事務或者邏輯,並同時保證頁面對用戶的及時響應。
Web Workers 為 Web 前端網頁上的腳本提供了一種能在后台進程中運行的方法。一旦它被創建,Web Workers 就可以通過 postMessage 向任務池發送任務請求,執行完之后再通過 postMessage 返回消息給創建者指定的事件處理程序 ( 通過 onmessage 進行捕獲 )。Web Workers 進程能夠在不影響用戶界面的情況下處理任務,並且,它還可以使用 XMLHttpRequest 來處理 I/O,但通常,后台進程(包括 Web Workers 進程)不能對 DOM 進行操作。如果希望后台程序處理的結果能夠改變 DOM,只能通過返回消息給創建者的回調函數進行處理。
主線程-----------------------------------------------------
var worker = new Worker('***.js');
--僅能存放同域的處理數據用,或ajax調用數據用的js,子線程的js不能操作dom節點,因為子線程不能影響主線程對dom的操作。
worker.postMessage(data); 通過postMessage方法來關聯主子線程。data為任意值
worker.terminate(); 終止workers,一旦終止則不能再使用,需要重新new worker
worker.message(); 接收信息用,放入監控中則一直有效。
worker.error(); 對錯誤的處理
子線程--------------------------------------------------------
子線程中的js可操作范圍:
worker.js執行的上下文與主頁面html執行時的上下文並不相同,最頂層的對象並不是window,而是WorkerGlobalScope。
因此window的alert方法在此js中不能用。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
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中就不行
示例:
加載報錯“Uncaught DOMException: Failed to construct 'Worker': ” --部分瀏覽器不允許本地加載外部文件,需要放在web容器中運行。
1 $(function($){ 2 if(typeof(window.Worker) != 'undefined'){ 3 var worker = new Worker('worker.js'); 4 worker.postMessage("主線程:請求處理數據------"); 5 worker.onmessage = function(e){ // 注意這里message是小寫 6 console.log("---" + e.data); 7 } 8 worker.onerror = function(e){ 9 console.log("---" + e.message); 10 worker.terminate(); 11 } 12 worker.postMessage("主線程:請求處理數據------"); 13 } 14 console.log("我只是飄過。。。。。"); 15 });
1 /** 2 * worker.js 的上下文頂級對象為WorkerGlobalScope,沒有document和windows對象。因此dom元素不能操作,windows的部分方法不能使用.注意保存的編碼格式 3 * DennyZhao 4 * Date:2017/9/22 5 */ 6 var self = this;
self.importScripts('script1.js'); //限定為WorkerGlobalScope對象內容
7 self.onmessage = function(event){
8 //console.log("-----work);//這個不起作用不支持console
9 self.postMessage(" 開始處理主線程的任務。。。。。。" + event.data);
10 var a = event.data;
11 a += "處理過程¥¥";
12 self.postMessage("主線程的任務處理完畢........" + a);
13 self.close(); 14 }
結果:
我只是飄過。。。。。
--- 開始處理主線程的任務。。。。。。主線程:請求處理數據------
---主線程的任務處理完畢........主線程:請求處理數據------處理過程¥¥
Cross-document messaging
Cross-document messaging 簡介
H5推出的信息隊列調用,可以解決兩個window之間的信息共享,iframe內外信息傳遞,本地調用遠端頁面到本地的跨域信息傳遞,方法調用等問題。
不過僅限於前台web的頁面之間調用,還沒辦法解決跨域的前台和后台的調用,還需用Ajax的jsonP形式進行傳遞。
postMessage采用異步通信的方式,因此可以做頁面的js動作和渲染用。同時不影響別的代碼繼續執行,提高處理速度。
1.本地自身使用消息隊列的postMessage(如果同時執行在同一個window上,會因為渲染和js處理同時進行導致並發出錯)
1 window.addEventListener('message',function(e){ 2 console.log("event------" + e.data); 3 },false); 4 // postMessage 5 $(function($){ 6 function postMessages(){ 7 window.postMessage("12345","/"); 8 console.log("--45678----"); 9 } 10 postMessages(); 11 }); 12 13 14 結果:異步執行動作 15 --45678---- 16 event------12345
2. iframe中的內外交互
在windows/system32/driver/etc/host 下,修改127.0.0.1
127.0.0.1 test.com
127.0.0.1 test2.com
這樣就形成跨域請求,如果不跨域時,可不設置。(以上為測試用)
1 <script type="text/javascript"> --父窗體 2 // postMessage 3 window.addEventListener("message", function(event){ 4 $("div").css("backgroundColor","#" + event.data); 5 }); 6 $(function($){ 7 //$("#myIframe")[0].contentWindow.postMessage("getMessage", "http://test2.com:8080"); 放此地方報錯,iframe的src還未裝載 8 $("button").click(function(){ 9 $("#myIframe")[0].contentWindow.postMessage("getMessage", "http://test2.com:8080"); //注意此處調用子url時需要iframe已經產生渲染完畢。 10 }); 11 12 13 }); 14 15 </script>
1 <script type="text/javascript"> --iFrame 2 var color= 50; 3 window.addEventListener("message", function(event){ 4 $('div').css("backgroundColor", "red"); 5 6 },false); 7 // postMessage 8 $(function($){ 9 10 $('div').click(function(){ 11 color = color + 100000; 12 $(this).css("backgroundColor", "#" + color); 13 window.top.postMessage(color, "http://test.com:8080"); 14 }); 15 16 }); 17 18 </script>
3. openWindow中使用
1 <script type="text/javascript"> 2 // postMessage 3 window.addEventListener("message", function(event){ 4 $("div").css("backgroundColor","#" + event.data); 5 }); 6 $(function($){ 7 //$("#myIframe")[0].contentWindow.postMessage("getMessage", "http://test2.com:8080"); 放此地方報錯,iframe的src還未裝載 8 $("button").click(function(){ 9 var child = window.open("http://test2.com:8080/webtest/worker/iFrame.html", "_blank"); 10 var my = setInterval(function(){ 11 if(child && !child.closed){ 12 child.postMessage("getMessage", "http://test2.com:8080"); //注意此處調用子url時需要window已經產生 13 clearInterval(my); 14 } 15 }, 200); 16 }); 17 18 19 }); 20 21 </script>
1 <script type="text/javascript"> 2 var color= 50; 3 window.addEventListener("message", function(event){ 4 $('div').css("backgroundColor", "red"); 5 6 },false); 7 // postMessage 8 $(function($){ 9 10 $('div').click(function(){ 11 color = color + 100000; 12 $(this).css("backgroundColor", "#" + color); 13 window.opener.postMessage(color, "http://test.com:8080"); 14 }); 15 16 }); 17 18 </script>
WebSockets
WebSockets 簡介
在 Web 應用中,HTTP 協議決定了客戶端和服務端連接是短連接,即客戶端 Request,服務端 Response,連接斷開。要想實現客戶端和服務端實時通信,只能通過客戶端輪詢來實現。服務端推送數據也並不是字面上意思上的直接推,其實還是客戶端自己取。WebSockets 是 HTML5 規范新引入的功能,用於解決瀏覽器與后台服務器雙向通訊的問題,使用 WebSockets 技術,后台可以隨時向前端推送消息,以保證前后台狀態統一。
在 WebSockets 中使用 send 和 onmessage發送和接收信息。
WebSockets 服務器端有 jetty 提供的基於 Java 的實現,有 WebSocket-Node 基於 node.js 的實現。
1.選用nodeJs作為服務器端應用(參見nodejs 創建webSocket)
1 var WebServer = require('ws').Server; 2 var wss = new WebServer({port:3500}); 3 wss.on('connection', function(ws){ 4 console.log('創建連接成功!'); 5 ws.on('message', function(msg){ 6 console.log(msg); 7 }); 8 setInterval(function(){ 9 ws.send(Math.random() * 10000); 10 },1000); 11 });
前台發送信息到后台: 1 <script type="text/javascript"> 2 $(function($){
3 var server = { 4 ws : {}, 5 connection : function(){ 6 this.ws = new WebSocket("ws://test.com:3500/"); 7 this.recieve(); 8 this.open(); 9 this.ws.onerror = function(error, data){ 10 console.log("error : " + error); 11 server.ws.close(); 12 } 13 }, 14 send : function(_msg){ 15 server.ws.send(_msg); 16 }, 17 recieve : function(){ 18 server.ws.onmessage = function(event){ 19 if(event.data){ 20 $("<div>").text(event.data).appendTo('body'); 21 } 22 } 23 }, 24 close : function(){ 25 server.ws = null; 26 }, 27 open : function(){ 28 server.ws.onopen= function(){
35 console.log("webSocket已經鏈接.......");
36 server.ws.send('webSocket已經創建');
47 } 48 }; 49 // 連接 50 server.connection(); 51 var i = 0; 52 var myInterval = setInterval(function(){ 53 i = i + 1; 54 server.send('發送 ' + i + ': '); 55 if(server.ws.readyState != 1){ 56 clearInterval(myInterval); 57 } 58 }, 1000); 59 }); 60 61 </script>
結果:

1 C:\Users\Administrator\Desktop\test\nodeJs>node websocket 2 創建連接成功! 3 webSocket已經創建 4 發送 1: 5 發送 2: 6 發送 3: 7 發送 4: 8 發送 5: 9 發送 6: 10 發送 7: 11 發送 8: 12 發送 9: 13 發送 10: 14 發送 11: 15 發送 12: 16 發送 13: 17 發送 14: 18 發送 15: 19 發送 16: 20 發送 17: 21 22 頁面接收部分:----- 23 4848.977736803326 24 7762.762571534494 25 3343.602966652355 26 1073.4970072202343 27 8700.747665594601 28 2556.6261964728064 29 3065.183213127105 30 134.2700772638583 31 7319.230923541 32 3183.5101594279868 33 6892.64312993447 34 1412.415079333049 35 6946.477577338111 36 4111.868595940827 37 5996.174673001297 38 4171.965367213602 39 1790.7039601051533
Server-Sent Events
HTML5 Server-Sent 事件模型允許您從服務器 push 實時數據到瀏覽器。與Web-Socket相比,Server-Sent Events 僅可由服務器向客戶端單方面推送信息,而不能有客戶端向服務端推送請求。好處是不用建立服務端的 WebSocket服務。
利用 Eventsource 對象處理與頁面間的接收和發送數據。在客戶端,我們使用 HTML5+JavaScript,服務端使用 Java。在現存的 Ajax 模式中,web 頁面會持續不斷地請求服務器傳輸新數據,由客戶端負責請求數據。而在服務端發送模式下,無需在客戶端代碼中執行連續的數據請求,而是由服務端 push 推送更新。一旦您在頁面中初始化了 Server-Sent 事件,服務端腳本將持續地發送更新。客戶端 JavaScript 代碼一旦接收到更新就將新的數據寫入頁面中展示出來。使用基於 Java 的 Servlet 技術實現服務器端。
為方便快捷,我們使用nodejs作為服務器端。
1 var http = require('http'); 2 const path = require('path'); 3 path.basename('index.html'); 4 var url = require('url'); 5 var fs = require('fs'); 6 var filehome = "./html"; 7 http.createServer(function(req,res){ 8 console.log(''); 9 // 文件系統 10 if(req.url.search(/\.html|\.js/i) > 0){ 11 filepath = filehome + req.url; 12 fs.readFile(filepath, function(error, data){ 13 if(error){ 14 res.writeHeader(404, {"Content-Type":"text/html;charset='utf-8'"}); 15 res.write('<h1>404錯誤</h1><p>你要找的頁面不存在</p>'); 16 res.end(); 17 }else{ 18 res.writeHeader(200, {"Content-Type":"text/html;charset='utf-8'"}); 19 res.write(data); 20 res.end(); 21 } 22 }); 23 return; 24 } 25 26 // 請求處理 27 var pathname = url.parse(req.url).pathname; 28 res.writeHeader(200, {"Content-Type":"text/event-stream"}); 29 if(pathname.search('/serverEvent') > -1){ 30 setInterval(function(){ 31 var date = new Date().getTime(); 32 var content = "data:" + date + "\n\n"; 33 res.write(content); 34 res.flushHeaders(); 35 //res.end(); 此處不能關閉,不然會中斷Server-Sent EVENT拋出error 36 }, 1000); 37 } 38 }).listen(3011, '127.0.0.1'); 39 40 console.log("啟動成功,請去http://127.0.0.1:3011 下嘗試。。。。");
客戶端:
1 $(function($){ 2 var source = new EventSource('http://127.0.0.1:3011/serverEvent'); 3 source.onmessage=function(event){ 4 $("<div>").text(event.data).appendTo('body'); 5 }; 6 source.onerror = function(error, event){ 7 $("<div>").text('Error is occur.....').appendTo('body'); 8 } 9 10 source.open=function(event){ 11 $("<div>").text("連接創建成功。。。。。").appendTo('body'); 12 }; 13 });