代码之家  ›  专栏  ›  技术社区  ›  Matt Ball

提高长轮询Ajax性能

  •  5
  • Matt Ball  · 技术社区  · 16 年前

    我在写一个webapp( 仅Firefox兼容 )它使用长轮询(通过jquery的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);
    }
    

    (半秒的“休眠”是这样,如果更新很快返回到客户机,客户机就不会锤击服务器—通常是这样的。)

    在让它运行一整夜之后,它会让火狐爬行。我一直在想,这可能部分是由于一个大的堆栈深度,因为我基本上写了一个无限递归函数。但是,如果我使用Firebug并向 fetch 似乎情况并非如此。Firebug向我展示的堆栈只有4到5帧深,即使在一个小时之后。

    我正在考虑的解决方案之一是将递归函数更改为迭代函数,但我无法确定如何在Ajax请求之间插入延迟 不旋转 . 我看过 JS 1.7 "yield" keyword 但我不能完全把我的头绕起来,想知道这是不是我需要的。

    最好的解决方案是定期对页面进行硬刷新,比如每小时刷新一次吗?是否有更好/更精简的长轮询设计模式,即使在运行8或12小时后也不会对浏览器造成伤害?或者我应该跳过长轮询,使用不同的“持续更新”模式,因为我通常知道服务器对我的响应频率如何?

    4 回复  |  直到 16 年前
        1
  •  2
  •   Jerod Venema    15 年前

    也有可能是火虫。您是console.logging,这意味着您可能打开了一个网络监视器选项卡,等等,这意味着每个请求都存储在内存中。

    尝试禁用它,看看是否有帮助。

        2
  •  2
  •   Daniel Vassallo    16 年前

    我怀疑记忆是从 processResults() .

    我在一个很长的轮询Web应用程序中使用了与您相似的代码,它可以连续运行数周而不刷新页面。

    你的堆栈不应该很深,因为 fetch() 立即返回。您没有无限递归循环。

    你可能想使用火狐 Leak Monitor Add-on 帮助您查找内存泄漏。

        3
  •  1
  •   Fabian Jakobs    16 年前

    堆叠深度4-5是正确的。 setTimeout $.ajax 是立即返回的异步调用。稍后,浏览器会使用空的调用堆栈调用回调。由于不能以同步方式实现长轮询,因此必须使用此递归方法。没有办法让它迭代。

    我怀疑这种减速的原因是您的代码有内存泄漏。泄漏可能在 阿贾克斯 通过jquery(非常不可能)或在您的 processResults 打电话。

        4
  •  1
  •   Felipe Leão    11 年前

    打电话是个坏主意 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()美元 呼叫在下一个呼叫开始前关闭。这可以通过添加一个简单的 console.log() 在前面和后面 $AXAX() 打电话。