Javascript 提高长轮询Ajax性能
我正在编写一个webapp(仅与Firefox兼容),它使用长轮询(通过jQuery的ajax功能)从服务器向客户端发送或多或少的持续更新。我担心长时间运行(比如整天或一夜)会产生什么影响。基本代码框架如下:Javascript 提高长轮询Ajax性能,javascript,ajax,performance,long-polling,Javascript,Ajax,Performance,Long Polling,我正在编写一个webapp(仅与Firefox兼容),它使用长轮询(通过jQuery的ajax功能)从服务器向客户端发送或多或少的持续更新。我担心长时间运行(比如整天或一夜)会产生什么影响。基本代码框架如下: function processResults(xml) { // do stuff with the xml from the server } function fetch() { setTimeout(function () { $.ajax
function processResults(xml)
{
// do stuff with the xml from the server
}
function fetch()
{
setTimeout(function ()
{
$.ajax({
type: 'GET',
url: 'foo/bar/baz',
dataType: 'xml',
success: function (xml)
{
processResults(xml);
fetch();
},
error: function (xhr, type, exception)
{
if (xhr.status === 0)
{
console.log('XMLHttpRequest cancelled');
}
else
{
console.debug(xhr);
fetch();
}
}
});
}, 500);
}
(半秒钟的“睡眠”是为了在更新很快返回到客户机时,客户机不会重击服务器—通常情况下是这样的。)
在让它运行一夜之后,它会让Firefox爬行。我一直认为这可能部分是由于堆栈深度过大造成的,因为我基本上编写了一个无限递归函数。但是,如果我使用Firebug并在fetch
中抛出一个断点,看起来情况并非如此。Firebug显示的堆栈只有4或5帧深,即使在一小时后也是如此
我正在考虑的一个解决方案是将递归函数改为迭代函数,但我不知道如何在Ajax请求之间插入延迟而不旋转。我已经看过了,但我不能完全把我的头围绕着它,以找出它是否是我在这里需要的
最好的解决方案是定期(比如每小时)对页面进行硬刷新吗?是否有更好/更精简的长轮询设计模式,即使在运行8或12小时后也不会对浏览器造成伤害?或者我应该完全跳过长轮询并使用不同的“持续更新”模式,因为我通常知道服务器会多长时间收到一次响应?我怀疑
processResults()
中有内存泄漏
我在一个长轮询web应用程序中使用了与您非常相似的代码,该应用程序能够连续运行数周而不刷新页面
堆栈不应该很深,因为fetch()
会立即返回。您没有无限递归循环
您可能希望使用Firefox来帮助您查找内存泄漏。堆栈深度4-5是正确的
setTimeout
和$。ajax
是异步调用,会立即返回。浏览器稍后会使用空调用堆栈调用回调。由于不能以同步方式实现长轮询,因此必须使用这种递归方法。没有办法使它迭代
我怀疑这种速度减慢的原因是您的代码存在内存泄漏。泄漏可能在jQuery的
$.ajax
中(可能性很小),也可能在您的processResults
调用中。也可能是FireBug。您是console.logging,这意味着您可能打开了一个网络监视器选项卡,等等,这意味着每个请求都存储在内存中
尝试禁用它,看看是否有帮助。从方法本身内部调用
fetch()
是个坏主意。当您期望在某个时候方法将到达终点并且结果将开始发送给调用方时,最好使用递归性。问题是,当您递归调用该方法时,它会保持调用方方法打开并使用内存。如果只有3-4帧深,那是因为jQuery或浏览器不知何故正在“修复”您所做的事情
jquery的最新版本默认支持长轮询。通过这种方式,您可以确保您不会依赖浏览器的智能来处理无限递归调用。调用$.ajax()
方法时,您可以使用下面的代码进行长时间轮询,并在新调用之前安全等待500毫秒
function myLongPoll(){
setTimeout(function(){
$.ajax({
type:'POST',
dataType: 'JSON',
url: 'http://my.domain.com/action',
data: {},
cache: false,
success:function(data){
//do something with the result
},
complete: myLongPoll,
async : false,
timeout: 5000
});
//Doesn't matter how long it took the ajax call, 1 milisec or
//5 seconds (timeout), the next call will only happen after 2 seconds
}, 2000);
通过这种方式,您可以确保在下一个调用开始之前,
$.ajax()
调用已关闭。这可以通过在调用$.ajax()
之前和之后分别添加一个简单的控制台.log()
来证明。我认为这是另一种“打破”堆栈深度的方法,但我看不出这与我的原始代码中的设置超时有任何不同的效果。是的,但是堆栈不应该深入,因为fetch()会立即返回,所以success和error函数很快就会从堆栈中消失。这是可能的。在FF中检测内存泄漏的最佳工具是什么?我刚刚意识到我已经很久没有在禁用Firebug的情况下运行它了。这很可能就是问题所在。@Bears:可能是,但我仍然设法让我的Firebug长轮询应用程序在没有页面刷新和明显内存泄漏的情况下打开了几天。但是,firebug可能会泄漏内存,因为processResults()
中存在合法的内容,而我的应用程序没有这样做。因此,是的,这可能是问题的原因。使用jQuery的complete
回调与我问题中的实现没有明显区别。这不是Java—调用者永远不需要显式关闭XHR或其他资源。