在现实上项目傍边,常常需要利用短轮询(每隔一按时间就向服务器发送一次请求,请求每每会立刻返回)和长轮询(每次请求办事器会Hold一段时间直到有新数据或超时,客户端收到数据后会当即进行下一次请求)来从服务器拉取数据,然后动态的更新页面。跟着功能的增添,一个页面中常常存在不止一个这样的轮询请求,并且在用户开启多个Tab页面时,总得请求数会翻倍。而“请求同步”指的是在以上场景中,即便是开启多个Tab也只有一个Tab页面保持轮询毗连,一旦数据返回后,就将数据同步到其他无毗邻的页面,最年夜水平的削减请求。实现的思绪也很简单,先解决由谁来进行请求的问题,以后基于本地存储将数据进行同步便可。具体的实现则有很多细节需要注重的,以下具体说明。
1、判断是否需要倡议请求
起首,短轮询和长轮询是有区此外:
短轮询不会长时间维持一个请求,平常都是请求数据返回后会隔一段时间再次发起请求。因此页面在判断自己是否需要发起请求时平日只需要判断:
1. 数据是否有效
2. 当前是否有其他页面已在请求中
3.请求是否已经超时
而长轮询时,每一个请求城市延续比力长的时间,请求一旦返回后会立即再次发送请求。这时候判断是否需要请求的根据是:
1. 当前是否有其他页面已经在请求中
2. 请求是否已经超时
在长轮询中因为两次请求之间凡是是不会有距离的,因此不会斟酌数据的有效性问题。
综合一下,不管长短轮询,一个页面需要尝试进行 请求的前提以下:
1. 当前数据已失效
当数据返回时会在当地存储中记实数据的返回时候,如许就能够计较数据的保存周期进而判定是不是失效;长轮询时会把数据的有用期设置为0,即始终认为数据是掉效的。
2.当前无其他页面在请求或请求已超时
当某个页面建议请求时会在本地存储中标志自己处于请求状况,请求返回后会再次符号自己状态为未请求。
别的,当一个请求发送后有可能会由于某些缘由超时,例如项目中长轮询的最大持续时间是50s,考虑各类误差,如果这个时间大于60s的话则可以视为超时。当本地存储中即使已经标记了有页面正在请求,可是请求已超时则也会被视为该当提议请求的一个条件。
较量争论请求是否超时的方式是在请求发送前在本地存储中纪录发送时间。
以下是上述条件判断的具体实现:
isDataValid: function(){
var st = this.storage,
timestamp = parseInt( st.getItem( this.timestampKey ), 10 );
return (new Date() * 1 - timestamp ) < this.interval;
},
isLive: function(){
var st = this.storage,
state = parseInt( st.getItem( this.stateKey ), 10 ),
timestamp = parseInt( st.getItem( this.timestampKey ), 10 );
var isLive = !!state && (new Date() * 1 - timestamp ) < this.liveAge;
return isLive;
}
另外,以上的判断进程每一个页面都邑使用一个Timer来按期的Check。
2、肯定请求权
解决了判断是否需要请求的问题后,下一步就是需要解决由谁来发请求的问题了。第一步中描写一个页面判断需要创议请求后是测验考试进行
要求,是以此时可能同时有N个页面都发现需要进行请求,此时就需要从N个当选择一个。
实现的体例仍然是借助本地存储解决的,方案如下:
1. 发生一个随机数A
2. 将A写入本地存储中,key为B
3. 40ms之后读取key为B的本地存储数据,若是其值为A则表白本身取得请求权,不然继续尝试连接
实际上就是操纵浏览器自己对写存储数据的并行节制来实现请求权简直定。
具体实现代码如下:
pk: function(win,lose){
var random = Math.random(),
ins = this,
st = this.storage;
var compare = function() {
var val = st.getItem( ins.pkKey );
if ( val == random ) {
win && win();
} else {
lose && lose();
}
};
st.setItem( this.pkKey, random);
setTimeout( compare, 40);
}
3、同步请求数据
以上两个问题解决后,数据同步的问题就更轻易解决了:
1. 所有页面使用Storage的onstorage接口监听具体的key 烦忙
KEY_A,一旦KEY_A产生转变就挪用响应的Callback
2. 当请求的数据返回时,将数据更新到KEY_A中
monitor: function(){
var st = this.storage,
ins = this;
if( ins.callback ){
st.onstorage( this.dataKey, function(data){
//只有当数据被其他页面点窜后才触发
if( !ins.localRequest ){
ins.callback( data );
}
});
}
}
4、使用
var p = new Poller({
url: 'gettime.php',
interval: 3000,
liveAge: 10000,
callback: function( data ){
if( p.localRequest ){
data += ' 数据来自当前页的Ajax请求';
}
else{
data += ' 数据来自其他页的数据同步';
}
$('#content').html( data );
}
});
p.start();
此外,假如阅读器不撑持本地存储或者手动设置了不使用本地存储则每个页面都会发送请求。
具体的演示实例请参考http://www.varnow.org/pages/html5/storage/sync/request_sync.html