long-poll jQuery.ajax()在手机休眠后无法回调?

时间:2015-12-17 17:37:06

标签: javascript jquery ajax google-chrome long-polling

我的网络应用使用“长轮询”方法来跟踪我服务器的最新数据。服务器只有在有新数据时才会响应,这可能相隔很多分钟。 (这是一个加热控制系统,您只能在室温变化或有人更改设置时看到更新。)

var version = "0";
function updater() {
    $.ajax({
        type: "POST",
        url: "/listen",
        data: version,
        success: function (data) {
            version = handleUpdates(data);
            updater();
        },
        error: function () {
            setTimeout(updater, 1000);
        }
    });
}

除了一种情况外,它在桌面浏览器和手机上运行良好。我发现在带有Chrome的Android手机上,在手机进入睡眠状态超过10分钟后会发生奇怪的事情。邮件请求似乎被删除,我认为这是合理的,因为手机是睡着了。在Chrome调试器的“网络”标签中,POST请求的状态文本显示(已取消)。

问题是当我取消请求时唤醒手机,调用success()或error()函数,我的网络应用程序永远不会更新。 $ .ajax()违背承诺给我回电话。

问题只发生在某些设备上。我已经能够通过借用朋友的设备进行一些临时测试。到目前为止,我只看到Android手机上的问题。但不是手机连接到充电器。我没有在苹果设备或Windows PC上看到它。

我尝试在ajax设置中添加超时:

     timeout: 120 * 1000,

这有帮助,因为error()函数最终在唤醒后最多调用2分钟。但我希望用户在1或2秒内看到更新。我不想让超时这么短,因为它会造成不必要的服务器流量。

我也试过通过在Can any desktop browsers detect when the computer resumes from sleep?中描述的一秒钟setInterval中寻找迟到来检测设备是否处于睡眠状态。 当我检测到唤醒时,我中止()帖子并启动另一个。这在大多数情况下都有帮助但事实证明这是不可靠的。有时时间事件似乎在睡眠期间保持正常滴答,并且无论如何都会取消发布请求。它并不像是一个可靠的解决方案。

我使用的是最新版本的jQuery:(2.1.2)和Chrome(47)。

5 个答案:

答案 0 :(得分:0)

我不确定这是否有效,我现在无法测试但是试一试

$(window).focus(function() {
    updater();
});

答案 1 :(得分:0)

过去我遇到过问题,当手机进入睡眠状态时,JavaScript调用会被暂停。我最终得到的解决方案是使用似乎暂停的window.setInterval(),但是当电话被唤醒时恢复生机。

所以我建议设置一个间隔,每隔一段时间取消一次呼叫并重新启动它。这可能有助于它通过手机睡眠生存。

大致类似于:

var myCall = $.ajax({...});

Window.setInterval (refreshCall(), 10000);

function refreshCall (){
    myCall.abort ();
    myCall = $.ajax({...});
}

答案 2 :(得分:0)

这样的高级观察者功能怎么样:

var restartTimer = null;
function updater(){
    $.ajax({
        type: "POST",
        url: "/listen",
        data: version,
        success: function (data) {
            version = handleUpdates(data);
            clearTimeout(restartTimer);
            updater();
        },
        error: function () {
            clearTimeout(restartTimer);
            setTimeout(updater, 1000);
        }
    });
}
//  Kick it when the phone wakes up.
$(window).focus(function(){
    restartTimer = setTimeout(function(){
        initializeAll();
    }, 6000);
    updater();
});

你知道$(窗口).focus会在手机唤醒时触发,所以你尝试更新器(),就像Almis建议的那样,但是有一个故障安全计时器。如果更新程序触发(在笔记本电脑或iOS上),计时器将被取消并且一切正常,但如果更新程序已用完,则故障安全计时器将在6秒内触发,并通过调用initializeAll()重新启动整个应用程序。

答案 3 :(得分:0)

setInterval如何存储调用时间,然后将上次调用时间与当前时间进行比较 - 如果间隔为10秒,则自上次运行后经过的时间为5分钟,你可以假设你刚从睡梦中醒来?然后中止当前的ajax调用,然后重新启动它。

答案 4 :(得分:0)

最好的答案是“不要那样做”。您正在让服务器等待响应,同时跟踪服务器端的更改。让服务器响应并在一段时间内进行jQuery ping。如果你想在没有状态改变的情况下阻止实际刷新,你可以包括lastchanged或haschanged,但是如果服务器以任何方式执行相同的工作,只需让它响应并等待下一次轮询。

setInterval(function () { 
    $.post({"/listen", version, function (data) {
        if(data.haschanged)
            version = handleUpdates(data);
    }).fail(function () {
        // any error correction on failed call
    });
}, 1000);