参考: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      });

 

posted on 2017-11-03 17:46  zhaoqiang1980  阅读(3720)  评论(0编辑  收藏  举报