实践中有时候需要两个浏览器窗口之间能进行简单的通讯,已有的解决方案是使用window.opener与使用window.open返回的一个Handler进行窗口之间的通讯,某种意义上解决了窗口之间通讯的问题,可是这样的方法局限在进行通讯的任何一个窗口都不能进行刷新动作,否则的话,Handler就会丢失,已有的通讯就会被破坏。
当然,使用js进行任意窗口之间稳定的通讯也是有方法的,就是使用cookie这种浏览器本地信息存储的机制来解决问题。其核心方法如下,仿照传统C/S通讯类似的方式,分为Client/Server两个部分:
Server部分:
- 在Cookie中创建两个字段xxx_HB,xxx_MSG。xxx_HB存储服务器上一次heartbeat发生的时间,xxx_MSG负责存储Client发送给Server的消息。
- 每次heartbeat发生的时候都即时更新xxx_HB内的时间戳,heartbeat之间的时间间隔应该尽可能小。
- 发生heartbeat时,如果发现xxx_MSG中有客户端发送的消息,则取走该消息,清空xxx_MSG字段,并且将消息发送给Server的on message event handler
...var CookieServer = function(address,messageCallback){ this._address = address; this._heartBeatKey = address + '_HB'; this._messageKey = address + '_MSG'; this._heartBeatTimer = null; this.onMessage = messageCallback; } CookieServer.prototype.listen = function(){ if(readCookie(this._heartBeatKey) != null){ throw('There is exists a server at this address!'); }; this._heartBeatTimer = setInterval(this._heartBeat.bind(this),10); } CookieServer.prototype._heartBeat = function(){ createCookie(this._heartBeatKey,(new Date()).getTime().toString(),100); var value = readCookie(this._messageKey); if(value == null || value == '') return; eraseCookie(this._messageKey); this.onMessage(value); }...
Client部分:
- 每次调用Client对象的send方法时,通过构造Client对象时传入的xxx参数,检测xxx_HB与当前时间的间隔,如果该间隔大于每次Server heartbeat发生的间隔越10倍左右(出于稳定性考虑),则判定Server timeout。
- 如果Server is online,则将xxx_MSG字段置为消息内容,模拟向服务器发送消息的过程。
var CookieClient = function(address){
var server = {};
server._address = address;
server._heartBeatKey = address + '_HB';
server._messageKey = address + '_MSG';
this.server = server;
var value = readCookie(this.server._heartBeatKey);
if(value == null || value == ''){
throw('There is not exist a server at address: ' + address);
}
}
CookieClient.prototype.send = function(message){
var timeSpan = (new Date()).getTime() - parseInt(readCookie(this.server._heartBeatKey));
if(timeSpan > 1000){
eraseCookie(this.server._heartBeatKey);
eraseCookie(this.server._messageKey);
throw('Server at address: ' + this.server._address + ' is time out!');
}
createCookie(this.server._messageKey,message,100);
}
对于C/S任何一方发生“通讯故障”的情况,代码中都有处理,就不再多说了,具体的可以看实际的代码以及演示。
最后补充一下,使用这个通讯模块,需要prototype.js的支持,因为用到了其中的Function.bind()方法。
Technorati: ajax, javascript, cookie, web develop