【问题标题】:Asynchronous JavaScript polling freezes the browser using setTimeout or setInterval异步 JavaScript 轮询使用 setTimeout 或 setInterval 冻结浏览器
【发布时间】:2015-08-14 14:18:41
【问题描述】:

我编写了一个轮询脚本来接收新创建的数据记录。我想每隔N 秒执行一次调用。

我尝试setTimeout() 和setInterval() 运行轮询异步,但是在执行Polling() 函数时都冻结了浏览器,这对我来说真的很奇怪。

我在页面加载时调用StarPolling() 函数。 APICall() 函数是 jQuery $.POST 函数,它在任何其他情况下都运行良好 - 并且是异步的。

这是我与setTimeout()一起使用的代码

var pollinginterval = 5000;
function StartPolling()
{
    setTimeout(Polling, pollinginterval);
}

function Polling()
{
    [... some code ...]

    var api_call = 'API_URL';
    var api_call_parameters = {
        [...]
    };
    APICall(api_call, api_call_parameters, function(json_response)
    {
        /* this is the callback belongs to the $.POST request */

        [... some code ...]

        setTimeout(Polling, pollinginterval);
    });
}

我尝试使用setInterval() 的版本非常相似,除了递归调用。

我不能为此使用 Workers 或 HTML5 套接字,因为必须支持跨浏览器。

有没有办法以真正的异步方式运行轮询,或者在不冻结浏览器的情况下通过 JavaScript 使用 新的“线程”?

更新: 这就是APICall() 的运作方式:

function APICall(call, parameters, success_callback)
{
    $.post(apibase + "" + call,parameters)
    .done(function(response){
        try
        {
            var json_response = $.parseJSON(response);
        }
        catch(error)
        {
            [...]
        }

        if(json_response.header.status == "OK")
        {
            success_callback(json_response);
        }
        else if(json_response.header.status == "error")
        {
            [...]
        }
    })
    .fail(function(error) {
        [...]
    });
}

更新:我正在同时使用普通和私人浏览器 (firefox) 窗口测试轮询以尝试该功能。我刚刚注意到,只有当两个窗口同时运行轮询时才会出现问题。

可能是firefox的bug……

【问题讨论】:

  • APICall 到底是做什么的?这就是问题所在。是在做同步AJAX吗?
  • 您是否对您的应用程序进行了概要分析?
  • 如果我是你;首先我要做的是删除 APICall 方法中的 ajax 调用,然后放一个 console.log 看看浏览器是否仍然挂起重复的间隔调用.....
  • 在调用 APIcall() 之前可能是 [ ... some code ...] 部分中的内容
  • 我在您的代码中没有看到任何会冻结浏览器的内容。

标签: javascript jquery ajax asynchronous polling


【解决方案1】:

OP 希望以不干扰主线程(即在后台线程中)的方式运行 Polling。做到这一点的唯一方法是使用他特别不想使用的 WebWorker。

关于event loops 的大量有趣阅读请参见W3 文档,但基本上浏览器中发生的所有事情都是单线程的。所有 javascript 都将发生在主线程上(网络工作者除外)。 setTimeout 和 setInterval 所做的只是排队一个回调,该回调将在 ~x 秒后在主线程中运行。

很抱歉,除了 web workers 没有别的办法了。

【讨论】:

    【解决方案2】:

    您可以使用这样的长轮询模式:

    (function Polling() {
        setTimeout(function() {
            $.ajax({ url: "server", success: function(response) {
                //your try/catch here
            }, dataType: "json", complete: Polling });
        }, 5000);
    })();
    

    所以轮询会在重新启动之前尝试完成,即使服务器作业很长...

    【讨论】:

    • 对,但他目前的模式有什么问题?为什么会冻结浏览器?
    • 可能在服务器端……即使服务器作业没有完成,它也会每5秒发出一次请求。
    • 但这只会停止请求,不会冻结浏览器。
    • 这已经类似于 OP 的当前模式,所以这不能回答问题。我看到的唯一区别是 OP 因错误而停止,而您的代码不断出现错误。那么这如何回答这个问题呢?
    • @Karbos 对,这对“冻结我的浏览器”问题没有任何影响。
    猜你喜欢
    • 2016-12-10
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 2017-05-20
    • 2020-06-29
    相关资源
    最近更新 更多