当队列里有多于两个调用的时候浏览器将不会响应
可以尝试这样做,在首次访问时打开任何一个加载了大量RSS的页(如Pageflakes, Netvibes, Protopage),在加载期间,你可以尝试着单击一个链接到另一个站点或者试着直接访问另一个站点,那么将会发现浏览器不会有任何响应。直到浏览器里所有队列的AJAX调用都完成之后,浏览器才能接受另一个活动。这是IE的一个比较糟糕的地方,同样Firefox和Opera就不会有此问题。
这个问题是当有大量的AJAX调用的时候,浏览器会将所有的调用放到一个队列里,在同一时间内只执行其中的两个。所以,如果你单击了某个链接或者转向另一个站点,那么浏览器必须等待在得到另一个调用之前正在执行的调用完成之后才会去处理。解决这个问题的办法就是防止浏览器在同一时间内有多于两个的调用在队列里。我们需要维持一个自己的队列,然后从这个队列里将一个一个调用的发到浏览器的队列中。
这个解决方案是很棒,它可以防止调用间的冲突:
Collapse
![]()
var GlobalCallQueue = ...{
![]()
_callQueue : [], // 保存web method的调用列表
![]()
_callInProgress : 0, // 浏览器目前处理的web method的编号
![]()
_maxConcurrentCall : 2, // 同一时间内执行调用的最大数
![]()
_delayBetweenCalls : 50, // 调用执行之间的延迟
![]()
call : function(servicePath, methodName, useGet,
![]()
params, onSuccess, onFailure, userContext, timeout)
![]()
...{
![]()
var queuedCall = new QueuedCall(servicePath, methodName, useGet,
![]()
params, onSuccess, onFailure, userContext, timeout);
![]()
![]()
![]()
Array.add(GlobalCallQueue._callQueue,queuedCall);
![]()
GlobalCallQueue.run();
![]()
},
![]()
run : function()
![]()
...{
![]()
/**//// 从队列里执行一个调用
![]()
![]()
![]()
if( 0 == GlobalCallQueue._callQueue.length ) return;
![]()
if( GlobalCallQueue._callInProgress <
![]()
GlobalCallQueue._maxConcurrentCall )
![]()
...{
![]()
GlobalCallQueue._callInProgress ++;
![]()
// 得到第一个调用队列
![]()
var queuedCall = GlobalCallQueue._callQueue[0];
![]()
Array.removeAt( GlobalCallQueue._callQueue, 0 );
![]()
![]()
![]()
// 调用web method
![]()
queuedCall.execute();
![]()
}
![]()
else
![]()
...{
![]()
// 达到最大并发数,不能运行另一个调用
![]()
// 处理中的webservice method
![]()
}
![]()
},
![]()
callComplete : function()
![]()
...{
![]()
GlobalCallQueue._callInProgress --;
![]()
GlobalCallQueue.run();
![]()
}
![]()
};
![]()
![]()
![]()
QueuedCall = function( servicePath, methodName, useGet, params,
![]()
onSuccess, onFailure, userContext, timeout )
![]()
...{
![]()
this._servicePath = servicePath;
![]()
this._methodName = methodName;
![]()
this._useGet = useGet;
![]()
this._params = params;
![]()
![]()
![]()
this._onSuccess = onSuccess;
![]()
this._onFailure = onFailure;
![]()
this._userContext = userContext;
![]()
this._timeout = timeout;
![]()
}
![]()
![]()
![]()
QueuedCall.prototype =
![]()
...{
![]()
execute : function()
![]()
...{
![]()
Sys.Net.WebServiceProxy.original_invoke(
![]()
this._servicePath, this._methodName, this._useGet, this._params,
![]()
Function.createDelegate(this, this.onSuccess), // 调用处理完成
![]()
Function.createDelegate(this, this.onFailure), // 调用处理完成
![]()
this._userContext, this._timeout );
![]()
},
![]()
onSuccess : function(result, userContext, methodName)
![]()
...{
![]()
this._onSuccess(result, userContext, methodName);
![]()
GlobalCallQueue.callComplete();
![]()
},
![]()
onFailure : function(result, userContext, methodName)
![]()
...{
![]()
this._onFailure(result, userContext, methodName);
![]()
GlobalCallQueue.callComplete();
![]()
}
![]()
};
![]()
QueueCall封装了一个web method调用,它拥有真实web服务调用的所有参数,并且重写了onSuccess和onFailure回调函数。我们想知道当一个调用完成或者失败了的时候,如何从队列里调出另一个调用。GlobalCallQueue保存了web服务调用的列表。无论何时,当一个web method被调用时,我们先要对GlobalCallQueue中的调用进行排队,并从我们自己的队列里一个一个的执行调用。这样就可以保证浏览器在相同的时间里不会有多于两个的调用,所以浏览器就不会停止响应。
为了确保队列是基于调用的,我们需要像之前那样再次重写ASP.NET AJAX的web method
Sys.Net.WebServiceProxy.original_invoke = Sys.Net.WebServiceProxy.invoke;
![]()
Sys.Net.WebServiceProxy.invoke =
![]()
function Sys$Net$WebServiceProxy$invoke(servicePath, methodName,
![]()
useGet, params, onSuccess, onFailure, userContext, timeout)
![]()
...{
![]()
GlobalCallQueue.call(servicePath, methodName, useGet, params,
![]()
onSuccess, onFailure, userContext, timeout);
![]()
}
![]()
