HTML5 postMessage 和 onmessage API 详细应用

在学习HTML5的时候发现一位大神的博文,解决了个人的很多疑惑,转载分享给大家
原文地址:https://www.cnblogs.com/sugar-tomato/p/4497108.html

以下是原文:

随着 HTML5 的发展,了解并熟悉 HTML5 的 API 接口是非常重要的。postMessage(send) 和 onmessage 此组 API 在 HTML5 中有着广泛的应用,比如 Web Workers 中应用此组 API 实现多个线程间 JavaScript 调用功能 ,Cross-document messaging 中实现两个不同域间 JavaScript 调用功能等等。本文主要介绍此组 API 在 Web Workers,Cross-document messaging,WebSockets 以及 Server-Sent Events 中的详细应用情况

至 2008 年 W3C 制定出第一个 HTML5 草案开始,HTML5 承载了越来越多崭新的特性和功能。它不但强化了 Web 系统或网页的表现性能,而且还增加了对本地数据库等 Web 应用功能的支持。其中,最重要的一个便是对多线程的支持。在 HTML5 中提出了工作线程(Web Workers)的概念,并且规范出 Web Workers 的三大主要特征:能够长时间运行(响应),理想的启动性能以及理想的内存消耗。Web Workers 允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的及时响应。

一、Cookie肿么了

cookie的缺陷是非常明显的

  1. 数据大小:作为存储容器,cookie的大小限制在4KB左右这是非常坑爹的,尤其对于现在复杂的业务逻辑需求,4KB的容量除了存储一些配置字段还简单单值信息,对于绝大部分开发者来说真的不知指望什么了。

  2. 安全性问题:由于在HTTP请求中的cookie是明文传递的(HTTPS不是),带来的安全性问题还是很大的。

  3. 网络负担:我们知道cookie会被附加在每个HTTP请求中,在HttpRequest 和HttpResponse的header中都是要被传输的,所以无形中增加了一些不必要的流量损失。

二、Web Workers

1、Web Workers 简介

Web Workers 为 Web 前端网页上的脚本提供了一种能在后台进程中运行的方法。一旦它被创建,Web Workers 就可以通过 postMessage 向任务池发送任务请求,执行完之后再通过 postMessage 返回消息给创建者指定的事件处理程序 ( 通过 onmessage 进行捕获 )。Web Workers 进程能够在不影响用户界面的情况下处理任务,并且,它还可以使用 XMLHttpRequest 来处理 I/O,但通常,后台进程(包括 Web Workers 进程)不能对 DOM 进行操作。如果希望后台程序处理的结果能够改变 DOM,只能通过返回消息给创建者的回调函数进行处理。

浏览器对 HTML5 支持情况可以参考网站 When can I use…

2、在 Web Workers 中使用 postMessage 和 onmessage

首先,需要在客户端页面的 JavaScript 代码中 new 一个 Worker 实例出来,参数是需要在另一个线程中运行的 JavaScript 文件名称。然后在这个实例上监听 onmessage 事件。最后另一个线程中的 JavaScript 就可以通过调用 postMessage 方法在这两个线程间传递数据了。

清单 1. 主线程中创建 Worker 实例,并监听 onmessage 事件

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Test Web worker</title> <script type="text/JavaScript">function init(){ var worker = new Worker('compute.js'); //event 参数中有 data 属性,就是子线程中返回的结果数据worker.onmessage= function (event) { // 把子线程返回的结果添加到 div 上document.getElementById("result").innerHTML += event.data+"<br/>"; }; }</script> </head> <body onload="init()"> <div id="result"></div> </body> </html>

在客户端的 compute.js 中,只是简单的重复多次加和操作,最后通过 postMessage 方法把结果返回给主线程,目的就是等待一段时间。而在这段时间内,主线程不应该被阻塞,用户可以通过拖拽浏览器,变大缩小浏览器窗口等操作测试这一现象。这个非阻塞主线程的结果就是 Web Workers 想达到的目的。

清单 2. compute.js 中调用 postMessage 方法返回计算结果

var i=0; function timedCount(){ for(var j=0,sum=0;j<100;j++){ for(var i=0;i<100000000;i++){ sum+=i; } } // 调用 postMessage 向主线程发送消息postMessage(sum); } postMessage("Before computing,"+new Date()); timedCount(); postMessage("After computing,"+new Date());

图 1. 浏览器中运行结果

三、Cross-document messaging

1、Cross-document messaging 简介

由于同源策略的限制,JavaScript 跨域的问题,一直是一个颇为棘手的问题。HTML5 提供了在网页文档之间互相接收与发送信息的功能。使用这个功能,只要获取到网页所在窗口对象的实例,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。 要想接收从其他窗口发送来的信息,必须对窗口对象的 onmessage 事件进行监听,其它窗口可以通过 postMessage 方法来传递数据。该方法使用两个参数:第一个参数为所发送的消息文本,但也可以是任何 JavaScript 对象(通过 JSON 转换对象为文本),第二个参数为接收消息的对象窗口的 URL 地址,可以在 URL 地址字符串中使用通配符’*'指定全部地。

2、在 Cross-document messaging 中使用 postMessage 和 onmessage

为了实现不同域之间的通信,需要在操作系统的 hosts 文件添加两个域名,进行模拟。

清单 3. hosts 文件中添加两个不同的域名

127.0.0.1 parent.com
127.0.0.1 child.com

在父网页中通过 iframe 嵌入子页面,并在 JavaScript 代码中调用 postMessage 方法发送数据到子窗口。

清单 4. 父页面中嵌入子页面,调用 postMessage 方法发送数据

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Test Cross-domain communication using HTML5</title> <script type="text/JavaScript">function sendIt(){ // 通过 postMessage 向子窗口发送数据document.getElementById("otherPage").contentWindow .postMessage( document.getElementById("message").value, "http://child.com:8080"); }</script> </head> <body> <!-- 通过 iframe 嵌入子页面 --> <iframe src="http://child.com:8080/TestHTML5/other-domain.html" id="otherPage"></iframe> <br/><br/> <input type="text" id="message"><input type="button" value="Send to child.com" onclick="sendIt()" /> </body> </html>

在子窗口中监听 onmessage 事件,并用 JavaScript 实现显示父窗口发送过来的数据。

清单 5. 子窗口中监听 onmessage 事件,显示父窗口发送来的数据

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Web page from child.com</title> <script type="text/JavaScript">//event 参数中有 data 属性,就是父窗口发送过来的数据window.addEventListener("message", function( event ) { // 把父窗口发送过来的数据显示在子窗口中document.getElementById("content").innerHTML+=event.data+"<br/>"; }, false );</script> </head> <body> Web page from http://child.com:8080 <div id="content"></div> </body> </html>

图 2. 父窗口嵌入子窗口

图 3. 父窗口发送数据到子窗口

四、WebSockets

1、WebSockets 简介

在 Web 应用中,HTTP 协议决定了客户端和服务端连接是短连接,即客户端 Request,服务端 Response,连接断开。要想实现客户端和服务端实时通信,只能通过客户端轮询来实现。服务端推送数据也并不是字面上意思上的直接推,其实还是客户端自己取。WebSockets 是 HTML5 规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用 WebSockets 技术,后台可以随时向前端推送消息,以保证前后台状态统一。

2、在 WebSockets 中使用 send 和 onmessage

由于文本主要介绍 postMessage(send) 和 onmessage 客户端 API 的应用,而 WebSockets 涉及到服务器端代码的实现,所以本文将选取最简单的服务器端框架来编写服务器代码。WebSockets 服务器端有 jetty 提供的基于 Java 的实现,有 WebSocket-Node 基于 node.js 的实现,在 .Net 4.5 中也直接提供了 WebSockets 的支持。本文将使用 WebSocket-Node 提供的示例代码,稍作修改作为 WebSockets 的服务器端。关于 node.js 的介绍以及使用请参考 node.js 官方网站 node.js,关于 WebSocket-Node 的使用请参考 WebSocket-Node。

首先,需要在客户端通过 JavaScript 代码 new 一个 WebSocket 实例出来,参数是实现 WebSocket 服务器端 URL 地址。然后在这个实例上监听 onmessage 事件接收服务器端发送过来的数据。当然,客户端也可以调用 send 方法,发送数据到服务器端。

清单 6. 创建 WebSocket 对象,并监听 onmessage 事件

 connect : function() { var location ="ws://localhost:8000/"; // 创建 WebSockets 并传入 WebSockets server 地址this._ws =new WebSocket(location); this._ws.onmessage=this._onmessage; //WebSockets 还提供了 onopen 以及 onclose 事件this._ws.onopen =this._onopen; this._ws.onclose =this._onclose; }

在 _onmessage 方法中,接收数据,并显示在页面上

清单 7. _onmessage 方法

 _onmessage : function(event) { //event 参数中有 data 属性,就是服务器发送过来的数据if (event.data) { var messageBox = document.getElementById('messageBox'); var spanText = document.createElement('span'); spanText.className ='text'; // 把服务器发送过来的数据显示在窗口中spanText.innerHTML = event.data; var lineBreak = document.createElement('br'); messageBox.appendChild(spanText); messageBox.appendChild(lineBreak); messageBox.scrollTop = messageBox.scrollHeight - messageBox.clientHeight; } },

在 _onopen 方法中,调用 _send 方法发送一条消息到服务器端,告之连接已经建立。在 _onclose 方法中,把 WebSocket 的实例设置成 null,释放资源。

清单 8. _onopen,_onclose 以及 send 方法

_onopen : function() { server._send("Client:Open WebSockets,"+new Date()); }, //message 参数就是客户端向服务器端发送的数据_send : function(message) { if (this._ws) this._ws.send(message); }, // 此方法提供外部代码调用send : function(text) { if (text !=null&& text.length >0) server._send(text); }, _onclose : function(m) { this._ws =null; }

把这些方法封装在一个 server 对象中,方便提供外部调用。用户只需要先调用 server 的 connect 方法建立连接,然后调用 send 方法发送数据。

清单 9. 封装客户端实现

var server = { // 对外主要提供 connect 和 send 方法connect : function() {...}, _onopen : function() {...}, _send : function(message) {...}, send : function(text) {...}, _onmessage : function(event) {...}, _onclose : function(m) {...} };

在服务器端,通过 JavaScript 语言简单修改 WebSocket-Node 中提供的 echo-server.js 示例即可。这里只展示关键代码部分,其它代码请参见 WebSocket-Node 示例。

清单 10. WebSockets 服务器端简单实现

 // 监听客户端的连接请求wsServer.on('connect', function(connection) { function sendCallback(err) { if (err) console.error("send() error: " + err); } // 监听客户端发送数据的请求connection.on('message', function(message) { if (message.type === 'utf8') {// 区别客户端发过来的数据是文本还是二进制类型connection.sendUTF( "Server:Get message:<br/>"+message.utf8Data, sendCallback ); } else if (message.type === 'binary') { connection.sendBytes(message.binaryData, sendCallback); } }); connection.on('close', function(reasonCode, description) { }); });

图 4. 点击 Connect 按钮

图 5. 输入内容,单击 Send Message 按钮

五、Server-Sent Events

1、Server-Sent Events 简介

HTML5 Server-Sent 事件模型允许您从服务器 push 实时数据到浏览器。本文我们将介绍利用 Eventsource 对象处理与页面间的接收和发送数据。在客户端,我们使用 HTML5+JavaScript,服务端使用 Java。在现存的 Ajax 模式中,web 页面会持续不断地请求服务器传输新数据,由客户端负责请求数据。而在服务端发送模式下,无需在客户端代码中执行连续的数据请求,而是由服务端 push 推送更新。一旦您在页面中初始化了 Server-Sent 事件,服务端脚本将持续地发送更新。客户端 JavaScript 代码一旦接收到更新就将新的数据写入页面中展示出来。

2、在 Server-Sent Events 中使用 onmessage

Server-Sent Events 和 WebSockets 有相同之处,WebSockets 实现了服务器端以及客户端的双向通信功能,而 Server-Sent Events 则仅是指服务器端到客户端的单向通信,而且 Server-Sent Events 同样需要服务器端的实现,本文将使用基于 Java 的 Servlet 技术实现服务器端。关于服务器端向客户端写数据的格式,可以参考 W3C 关于 Server-Sent Events 的规范文档 Server-Sent Events。由于是服务器端到客户端的单向通信,所以在 Server-Sent Events 中没有 postMessage 方法。

首先,在客户端通过 JavaScript 代码 new 一个 EventSource 实例出来,参数是实现 EventSource 服务器端 URL 地址。然后在这个实例上监听 onmessage 事件接收服务器端发送过来的数据。

清单 11. 创建 EventSource 对象,并监听 onmessage 事件

if (!!window.EventSource) { // 创建 EventSource 实例,传入 server 地址var source = new EventSource('/TestHTML5/ServerSentEvent'); } else { console.log("Your browser doesn't support server-sent event"); } // 监听 message 事件,等待接收服务器端发送过来的数据source.addEventListener('message', function(event) { //event 参数中有 data 属性,就是服务器发送过来的数据console.log(event.data); }, false); //EventSource 还提供了 onopen 以及 onerror 事件source.addEventListener('open', function(event) { }, false); source.addEventListener('error', function(event) { if (event.readyState == EventSource.CLOSED) { } }, false);

服务器端,在 Java 语言实现的 Servlet doGet 方法中使用 response 对象向客户端写数据

清单 10. 服务器端简单实现

 // 这里必须设置 Content-Type 为 text/event-streamresponse.setHeader("Content-Type", "text/event-stream"); response.setHeader("Cache-Control", "no-cache"); response.setCharacterEncoding ("UTF-8"); String id = new Date().toString(); response.getWriter().println("id:"+id); // 向客户端写两行数据response.getWriter().println("data:server-sent event is working."); response.getWriter().println("data:test server-sent event multi-line data"); response.getWriter().println(); response.getWriter().flush();

图 6. Server-Sent Events 运行结果

3、为什么比cookie好

  1. 从容量上讲WebStorage一般浏览器提供5M的存储空间,用来存储视频、图片神马的不够,但对于绝大部分操作足矣

  2. 安全性上WebStorage并不作为HTTP header发送的浏览器,所以相对安全

  3. 从流量上讲,因为WebStorage不传送到服务器,所以不必要的流量可以节省,这样对于高频次访问或者针对手机移动设备的网页还是很不错的。

这并不意味着WebStorage可以取代cookie,而是有了WebStorage后cookie能只做它应该做的事情了——作为客户端与服务器交互的通道,保持客户端状态。所以仅仅作为本地存储解决方案WebStorage是优于cookie的。

注意点

  1. 浏览器兼容性,这个几乎是所有HTML5新特性中最容易实施的了,因为IE8+的浏览器都支持,在IE7、IE6中可以使用IE User Data实现。
  2. 由于localStorage和sessionStorage都是对象,所以我们也可以通过”.key”或”[key]”的方式获取、修改键值对,但不推荐这么做
localStorage.userName='Frank';
console.log(localStorage['userName']);
  1. 虽然localStorage存储在本地,但不同的浏览器存储存储数据是独立的,所以在Chrome上存储的localStorage在FireFox上是获取不到的。

  2. localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理,低版本IE可以使用json2.js

  3. 除了控制台,Chrome还为本地存储提供了非常直观的显示方式,调试的时候很方便

六、结束语

本文详细介绍了 postMessage(send)和 onmessage API 在客户端的应用情况,可以看到在不同的场景中这两个方法的应用模式都是类似的。postMessage 的作用就是传递数据,而 onmessage 的作用就是接收数据。掌握此组 API 对以后开发 HTML 5 应用程序将会有所帮助。本文 Web Workers,Cross-document messaging,WebSockets 的代码在 Firefox 14 下通过测试,Server-Sent Events 的代码在 Chrome 16 下通过测试。

HTML5 postMessage 和 onmessage API 详细应用相关推荐

  1. html游戏全屏代码,HTML5全屏(Fullscreen)API详细介绍

    在越来越真实的web应用程序中,JavaScript也变得越来越给力. FullScreen API 是一个新的JavaScript API,简单而又强大. FullScreen 让我们可以通过编程的 ...

  2. html谷歌全屏像素,HTML5全屏(Fullscreen)API详细介绍

    在越来越真实的web应用程序中,JavaScript也变得越来越给力. FullScreen API 是一个新的JavaScript API,简单而又强大. FullScreen 让我们可以通过编程的 ...

  3. html5 自动设置全屏,HTML5全屏(Fullscreen)API详细介绍

    在越来越真实的web应用程序中,JavaScript也变得越来越给力. FullScreen API 是一个新的JavaScript API,简单而又强大. FullScreen 让我们可以通过编程的 ...

  4. IBM Java多线程 - 6.其它线程 API 详细信息

    其它线程 API 详细信息 1. wait().notify() 和 notifyAll() 方法 2. 线程优先级 3. 线程组 4. SwingUtilities wait().notify() ...

  5. [转]html5: postMessage解决跨域和跨页面通信的问题

    [转]html5: postMessage解决跨域和跨页面通信的问题 参考文章: (1)[转]html5: postMessage解决跨域和跨页面通信的问题 (2)https://www.cnblog ...

  6. html约束验证的例子,HTML5利用约束验证API来检查表单的输入数据的代码实例

    HTML5对于表单有着极大程度的优化,无论是语义,小部件,还是数据格式的验证.我猜你肯定会以浏览器兼容作为借口不愿意使用这些"新功能",但这绝不应该成为使你停滞不前的原因,况且还有 ...

  7. html5获取地理位置信息API

    html5获取地理位置信息API 在HTML5中,可以看下如何使用Geolocation API来获得用户的地理位置信息,如果该浏览器支持的话,且设备具有定位功能,就能够直接使用这组API来获取当前位 ...

  8. HTML5关于上传API的一些使用(上)

    HTML5提供了很多有用的API,其中就包括上传的API,XMLHttpRequest2.0,在HTML5时代之前,需要进行二进制的上传一般都会才用flash的方案,但是当XMLHttpRequest ...

  9. html5 定位 计算距离,HTML5 地理定位+地图 API:计算用户到商家的距离

    背景 最近在做一个类似支付宝口碑商家的功能模块,其中有个功能就是计算出用户与商家的距离,如下图: 支付宝口碑商家页面截图 思路分析 1.商家选取店铺地址,将坐标经纬度存入数据库: 2.移动端定位当前用 ...

最新文章

  1. mysql 日期时间格式化字符串_MySQL日期函数与日期转换格式化函数大全
  2. 编写你的第一个 Django 应用,第 4 部分
  3. R语言观察日志(part17)--.Primitive
  4. P1064 [NOIP2006 提高组] 金明的预算方案
  5. kie-api_KIE-WB / JBPM控制台Ng –配置
  6. 洛谷 P1352 没有上司的舞会【树形DP/邻接链表+链式前向星】
  7. HTML table 和 div
  8. Mysql 格式化日期格式
  9. websoc是什么可以卸载吗_购房诚意金是什么意思?可以退吗?
  10. mySAP标准培训教材全套列表
  11. 大数据Python学习大纲
  12. 硬盘格式化了的数据找到方案
  13. 3Ds max彻底卸载方法
  14. python爬虫图书信息并存入数据库,以及安装工具库
  15. TOEFL wordlist 28
  16. H5打造属于自己的视频播放器(JS篇1)
  17. wp教程-wp详细教程-免费wordpress模板主题搭建教程
  18. vue监测数据的原理
  19. 解决win10服务主机:网络服务占用网络宽带的方法(自测有效)
  20. 牛奶洗面--对付脸色暗沉

热门文章

  1. 工业机器人智能制造生产线教学案例
  2. window常用终端命令
  3. 苹果使用过程的一些小技巧
  4. 西电计算机通信原理,西电通信原理大作业
  5. 你知道5分钟法则和10字节法则么?
  6. 【C++/数据结构】先序遍历+中序遍历构建二叉树
  7. Traffic Manager
  8. mt2503 如何使用META DLL API写两个以上IMEI
  9. Nodejs+Koa2+云服务ECS 开发微信公众号(一)之环境配置
  10. linux 重新运行命令,如何在Linux中重新运行最后执行的命令?