文章目录
  1. 1. 工作线程 Web Workers
  2. 2. 跨文档消息机制 Cross-document messaging
  3. 3. 小结
  4. 4. 参考

HTML5 有众多的崭新特性和功能,它强化了web系统|网页的表现性能,也增加了对本地数据库等 Web 应用的支持。在它的众多 API 接口中,其中 postMessage(send) 和 onmessage 有着广泛的应用。比如:

  1. Web Workers(工作线程)用它们实现多个线程间的 js 调用功能
  2. Cross-document messaging(跨文档消息机制) 中实现两个不同域间 js 调用功能
  3. WebSockets(浏览器本身可请求+服务器的推送)实现浏览器与后台服务器双向通讯
  4. 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 事件

1
2
3
4
5
6
function init(){
var worker = new Worker('compute.js'); // 子线程在 compute.js 中处理
worker.onmessage = function(event){
console.log( event.data ); // 输出子线程返回的结果数据
}
}

另一个线程 compute.js 中调用 postMessage 方法向主线程中发送消息,从而实现在两个线程间的数据传递

1
2
3
4
// 每隔1秒给主线程发送一个数据
setTimeout(function(){
postMessage("子线程向主线程发送的数据");
}, 1000);

跨文档消息机制 Cross-document messaging

HTML5 提供了在网页文档之间相互接收和发送消息的功能。只需要获取到网页所在的窗口对象实例,两个 Web 页面就可以相互通信了,甚至是跨域的。postMessage 允许页面中多个 iframe/window 间的通信。

  1. 要想接收从其他窗口发送来的信息,只需要监听窗口对象的 onmessage 事件即可。
  2. 一个窗口想要发送消息,则通过 postMessage(message, “”) 来传递数据。两个参数代表的含义分别是:
    第一个参数表示所要发送的消息文本,可以是任何 js对象(一般都通过 JSON 把对象转化成文本);
    第二个参数表示接收消息的对象窗口的url地址,通配符星号 指定全部地址。
    不用通配符也可以指定具体的 url,那么在 onmessage 中加个来源判断
    if( event.origin !== ‘xxxx’ ) return;

示例2. 模拟不同域间的通信,比如父页面中嵌了个 iframe 子页面,且父子是不同源的。
父页面给子页面发送消息,子页面接收

1
2
3
4
5
6
7
// 父页面中:父向子发
document.getElementById('iframeId').contentWindow.postMessage('父向子发送的数据');
// 子页面中:子对消息监听,随时接收数据
window.addEventListener('message', function(event){
console.log(event.data);
});

与之对应,如果子页面给父页面发消息的话,如下:

1
2
3
4
5
6
7
// 父页面中:监听
window.addEventListener('message', function(event){
console.log(event.data);
});
// 子页面中:子对父发消息
window.parent.postMessage('子向父发送的数据');

简而言之,发送消息的 postMessage() 和 监听消息的 onmessage 得是一对,即:

  1. 父给子发,那就调 子.postMessage 去给子发消息,然后 子.onmessage 去监听收
  2. 子给父发,那就掉 父.postMessage 去给父发消息,然后 父.onmessage 去监听收

说明:代码示例不考虑浏览器的兼容性,只为了说明原理。

小结

可见在不同场景中这两个 API 的应用模式都是类似的。postMessage 传递数据,而 onmessage 接收数据。

浏览器对这个 API 的支持情况,目前支持的有 ie8+ ,ff,chrome,opera,safari。HTML5 的 postMessage 可以解决大部分场景下的跨域问题,可以不用再创建代理的 iframe 去解决跨域(ie6 和 ie7)。

检测浏览器是否支持可用 !!window.postMessage == true 则支持

参考

  1. HTML5 postMessage 和 onmessage API 详细应用
  2. 利用 HTML5 的 window.postMessage 实现跨域通信
文章目录
  1. 1. 工作线程 Web Workers
  2. 2. 跨文档消息机制 Cross-document messaging
  3. 3. 小结
  4. 4. 参考