HTML5 中的 postMessage 和 onmessage
更新日期:
HTML5 有众多的崭新特性和功能,它强化了web系统|网页的表现性能,也增加了对本地数据库等 Web 应用的支持。在它的众多 API 接口中,其中 postMessage(send) 和 onmessage 有着广泛的应用。比如:
- Web Workers(工作线程)用它们实现多个线程间的 js 调用功能
- Cross-document messaging(跨文档消息机制) 中实现两个不同域间 js 调用功能
- WebSockets(浏览器本身可请求+服务器的推送)实现浏览器与后台服务器双向通讯
- Server-Sent Events 该事件模型允许从服务器实时推送数据到浏览器。
此处主要讨论 postMessage 在 Web Workers 和 Cross-document messaging 的应用。其他两个详见参考[1]。
工作线程 Web Workers
HTML5 中提出了工作线程 Web Workers 的概念,它指出 Web Workers 的三大主要特征:能长时间运行(响应)、理想的启动性能、理想的内存消耗。Web Workers 允许开发人员编写长时间运行而不被用户所中断的后台程序,去执行事务或逻辑,并同时保证页面对用户的及时响应。它为 Web 网页的脚本提供了一种能在后台进程中运行的方法。
一旦它被创建,Web Workers 就可以通过 postMessage 向任务池发送任务请求,执行完后再通过 onmessage 进行捕获。若想通过此机制改变 DOM,只能通过返回消息给创建者的回调函数进行处理。
示例1. 主线程和子线程如何通信:子发送,主监听
主线程中创建 Worker 实例,并监听 onmessage 事件
|
|
另一个线程 compute.js 中调用 postMessage 方法向主线程中发送消息,从而实现在两个线程间的数据传递
|
|
跨文档消息机制 Cross-document messaging
HTML5 提供了在网页文档之间相互接收和发送消息的功能。只需要获取到网页所在的窗口对象实例,两个 Web 页面就可以相互通信了,甚至是跨域的。postMessage 允许页面中多个 iframe/window 间的通信。
- 要想接收从其他窗口发送来的信息,只需要监听窗口对象的 onmessage 事件即可。
- 一个窗口想要发送消息,则通过 postMessage(message, “”) 来传递数据。两个参数代表的含义分别是:
第一个参数表示所要发送的消息文本,可以是任何 js对象(一般都通过 JSON 把对象转化成文本);
第二个参数表示接收消息的对象窗口的url地址,通配符星号 指定全部地址。
不用通配符也可以指定具体的 url,那么在 onmessage 中加个来源判断
if( event.origin !== ‘xxxx’ ) return;
示例2. 模拟不同域间的通信,比如父页面中嵌了个 iframe 子页面,且父子是不同源的。
父页面给子页面发送消息,子页面接收
|
|
与之对应,如果子页面给父页面发消息的话,如下:
|
|
简而言之,发送消息的 postMessage() 和 监听消息的 onmessage 得是一对,即:
- 父给子发,那就调 子.postMessage 去给子发消息,然后 子.onmessage 去监听收
- 子给父发,那就掉 父.postMessage 去给父发消息,然后 父.onmessage 去监听收
说明:代码示例不考虑浏览器的兼容性,只为了说明原理。
小结
可见在不同场景中这两个 API 的应用模式都是类似的。postMessage 传递数据,而 onmessage 接收数据。
浏览器对这个 API 的支持情况,目前支持的有 ie8+ ,ff,chrome,opera,safari。HTML5 的 postMessage 可以解决大部分场景下的跨域问题,可以不用再创建代理的 iframe 去解决跨域(ie6 和 ie7)。
检测浏览器是否支持可用 !!window.postMessage == true 则支持