论坛首页 Web前端技术论坛

基于HTML5 LocalStorage设计的跨页面通信模型

浏览 5225 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-09-01   最后修改:2011-09-01
  处女贴,大牛们轻拍 ~~

  最近在做一个webim项目,涉及到多点登陆的功能开发。该功能的核心是跨页面通信,最常用的手段当然是Flash的localConnection。大家都知道,使用LocalStorage进行同域下的跨页面通信是非常容易实现的,但是LocalStorage是针对所有页面生效的,如果考虑存在多个页面时希望可以进行点对点通信、数据组发等,事情就变得有点复杂了。

  考虑多点登陆需求中最常见的场景:访客可以打开多个页面,但同时只有一个页面保持与服务器连接;当另一个页面获得焦点时,当前正与服务器保持连接的页面应当断开该连接,并将页面状态传递给获得焦点的页面,新页面立即与服务器建立连接。

  为了实现以上场景,这个多点登陆模型应当具备以下基本特征:
  在以上场景中,假设我们称“当前正与服务器保持连接的页面”为“活动页面(MainPage)”,其他页面为“非活动页面(SubPage)”,则任意时刻MainPage只有一个,其他页面均为SubPage;
  任意一个SubPage应当可以使自己成为MainPage,同时原来的MainPage则转换为SubPage;
  MainPage和SubPage之间可以传递数据。

  我们期望这个模型可以完全隐藏实现方案,从通信的角度来说我更希望该模型能提供如下功能:
  页面A可以向发送一个Ajax请求发送Post一样,向页面B发送一个请求,可以携带参数,并允许获取页面B的返回数据以执行回调,例如:
A.someKindOfSend(B, key, param, callback)
;
  页面B可以添加一个Action用于处理某key标注的请求,并且返回处理结果,类似
B.someKindOfAddListener(key, handler)
;
  MainPage可以向所有SubPage发送请求;

  在保证基本功能完整性的情况下,该模型对页面通信做了一些限制,以使逻辑最简:
  SubPage之间无法直接通信;
  SubPage可向MainPage发送请求,因此如果两个SubPage之间希望通信,应当将其中一个SubPage转换为MainPage。

  另外,由于该模型基于LocalStorage封装,因此也应当能提供基本容器方法:add、set、get、remove。出于稳定性考虑,不提供全局查询和清空操作。

  综上,该模型的接口可设计为:
MultiPageUtil: {
  //跨页面通信控制
  controller : {
    //检测当前页面是否为活动页面
    isMainPage : function(){},

    /**
     *使当前页面转换为活动页面。如果当前页面已经是一个活动页面,则什么也不做
     *@param callback{Function} 转换成功后的回调函数
     */
    active : function(callback){},

    /**
     *对一个来自其他页面的Post事件添加处理器。
     *该方法区分来源,即MainPage能监听来自所有SubPage的事件,
     *SubPage仅能监听来自MainPage的事件。
     *@param key {String} 需要监听的属性key
     *@param handler {Function(e)} 被监听的key的value发生变化时的处理函数。传入参数为onstorage标准事件对象,handler的返回值将作为post请求中callback方法参数中标注事件e的newValue。如果为一个字段指定了多个listener,则该post的请求会收到多次响应。
     */
    addPostListener : function(callback){},

    /**
     *如果当前页面是一个SubPage,则该方法将向活动页面发送一个请求。
     *@param key {String} 请求标志位,类似Ajax请求中的URL
     *@param value {String} 请求数据,可用于传递请求参数并在对应的事件处理器中通过e.newValue获取
     *@param [callback] {Function} 请求响应函数。该函数将接收来自MainPage关于该请求的回复字符串
     */
    postMainPage : function(callback){},

    /**
     *如果当前页面是一个MainPage,则该方法将向活动页面发送一个请求。
     *@param key {String} 请求标志位,类似Ajax请求中的URL
     *@param value {String} 请求数据,可用于传递请求参数并在对应的事件处理器中通过e.newValue获取
     *@param [callback] {Function} 请求响应函数。该函数将接收来自MainPage关于该请求的回复字符串。注意,如果当前存在多个非活动页面,callback将可能被执行多次。
     */
    postSubPages : function(callback){}
  },

  //封转原LocalStorage处理的工具集
  util : {
    add : function(key, value){},
    set : function(key, value){},
    get : function(key){},
    remove : function(key, value){},
			
    /**
     *对一个来自localStorage中的某个属性变化事件添加处理器
     *支持添加多个处理器
     *该方法不区分来源。
     *@param key {String} 需要监听的属性key
     *@param handler {Function(e)} 被监听的key的value发生变化(由基本容器方法触发)时的处理函数,e为storage标准事件对象
     */
    addListener : function(key, handler) {}
  }


  到此为止,这个模型看起来还算比较可行,不过,在真正用LocalStorage实现时还需要处理一些额外的问题:
  1.基本思想:模型通过localStorage的标准事件onstorage来实现跨页面通信,即页面A通过写入特定数据触发页面B的onstorage事件,页面B响应之后再写入数据通知页面A处理结果;
  2.浏览器兼容性问题,老生常谈了,包括事件监听器绑定机制、标准事件属性支持程度等;
  3.事件筛选:LocalStorage对应的标准事件onstorage,在一个页面中对LocalStorage进行修改时所有页面均会收到该事件,有的浏览器甚至包括LocalStorage的修改者也会受到。因此,需要在存入的key中添加特定的标志位,以防止不应该响应该事件的页面对事件做出错误的处理。(例如,SubPage应当忽略除来自MainPage之外的所有Post请求);
  4.LocalStorage全局域字段污染问题:由1可知,Post请求实质仍然是往LocalStorage中写入数据,普通的处理很有可能将用户写入LocalStorage的普通数据覆盖,从而产生污染。可考虑使用特殊字段时间戳标记的方式防止污染。
  5.垃圾数据:大量的Post请求如果不进行清理,则会长期滞留在浏览器划分给LocalStorage在该域下的空间内。因此,每一个Post请求在被处理之后,都应当清空用于发送该Post而在LocalStorage中写入的数据;同时,callback、handler等函数是由绑定在onstorage事件的最上层处理器执行的,而callback应当是一次性的,因此执行之后也应当被处理。

  相信看到这里各位一定有许多想法,不妨留下您的意见来一起探讨探讨。附件中的代码是该模型的实现,目前的设计还有很多值得优化的地方,代码逻辑写到后期也有些紊乱和冗余...开发环境为Firefox6+、Chrome13。

  关于HTML5 localStorage的介绍请参见此处:http://www.webjx.com/web/xindejiqiao-24894_3.html由于未标注出处,实在没找到原作者,敬请见谅咯~

  Many 3X!
   发表时间:2011-09-13  
之前做过类似项目,有几点心得分享一下:
一开始我们也考虑使用LocalStorage,但后来放弃了。
最大的原因是当时还是要求支持IE6,只能使用UserData代替LocalStorage。使用UserData实在是有诸多限制:
1,IE6下,UserData一般状况下只能存储128K的数据,如果你做webim,假设要同步用户登录信息,聊天记录与消息数量,IM的用户好友数一多,这点大小就根本不够用了。
2,假设控制同步的信息,还有另外的问题:IE6,只有IE6下,UserData使用中如果发现跨了路径,页面之间是不能共用一个UserData数据的。这点你可以在MSDN上去查。

onstorage事件貌似还存在一些兼容性问题,你可能需要看看这篇文章:http://m.udpwork.com/item/5588.html

如果你做的这个项目打算放弃IE6,IE7用户,倒是可以多试试。
需要注意的地方有这几点:
1,主从切换是否存在延时。
2,多页面同步数据,小心广播风暴阻塞浏览器。(每个页面收到数据,尤其是初始化数据都会运行程序,如果同一事件有太多页面同事处理事件,有可能会造成页面假死)
3,如果要做客户端同步,可能只能有一个页面建立连接,其他页面作为从页面接收数据,否则难以达到同步。
4,注意用户安全问题,这是个很大的坑。
0 请登录后投票
   发表时间:2011-09-13  
pillar0514 写道
之前做过类似项目,有几点心得分享一下:
一开始我们也考虑使用LocalStorage,但后来放弃了。
最大的原因是当时还是要求支持IE6,只能使用UserData代替LocalStorage。使用UserData实在是有诸多限制:
1,IE6下,UserData一般状况下只能存储128K的数据,如果你做webim,假设要同步用户登录信息,聊天记录与消息数量,IM的用户好友数一多,这点大小就根本不够用了。
2,假设控制同步的信息,还有另外的问题:IE6,只有IE6下,UserData使用中如果发现跨了路径,页面之间是不能共用一个UserData数据的。这点你可以在MSDN上去查。

onstorage事件貌似还存在一些兼容性问题,你可能需要看看这篇文章:http://m.udpwork.com/item/5588.html

如果你做的这个项目打算放弃IE6,IE7用户,倒是可以多试试。
需要注意的地方有这几点:
1,主从切换是否存在延时。
2,多页面同步数据,小心广播风暴阻塞浏览器。(每个页面收到数据,尤其是初始化数据都会运行程序,如果同一事件有太多页面同事处理事件,有可能会造成页面假死)
3,如果要做客户端同步,可能只能有一个页面建立连接,其他页面作为从页面接收数据,否则难以达到同步。
4,注意用户安全问题,这是个很大的坑。


ho~只为尝鲜罢了,实际上IE8都无法支持,因为IE8的onstorage事件对象不携带url以外的数据。

广播风暴的话,使用了点对点机制,每个页面中维护一个可接收的来源页面id,非该来源的数据全部丢弃。

问题蛮多的,嘎嘎~
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics