提问人:James 提问时间:12/18/2015 最后编辑:CommunityJames 更新时间:1/6/2018 访问量:1394
long-poll jQuery.ajax() 在手机休眠后无法回调?
long-poll jQuery.ajax() fails to callback after phone sleeps?
问:
我的 Web 应用程序使用“长轮询”方法来保持来自我的服务器的最新数据。服务器仅在有新数据时才响应,这些数据可能相隔数分钟。(这是一个供暖控制系统,只有在室温变化或有人更改设置时,您才能看到更新)。
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() 函数,我的 Web 应用程序永远不会更新。$.ajax() 违背了给我回电话的承诺。
该问题仅在某些设备上发生。我已经能够通过从朋友那里借用设备来做一些临时测试。到目前为止,我只在安卓手机上看到了这个问题。但不是手机连接到充电器。我没有在任何平板电脑、苹果设备或 Windows PC 上看到它。
我尝试在ajax设置中添加超时:
timeout: 120 * 1000,
这很有帮助,因为 error() 函数最终会在唤醒后 2 分钟内调用。但我希望用户在 1 或 2 秒内看到更新。我不想让超时时间这么短,因为它会产生不必要的服务器流量。
我还尝试通过在一秒钟的 setInterval 中查找延迟来检测设备是否处于睡眠状态,如任何桌面浏览器都可以检测到计算机何时从睡眠状态恢复?中所述。 当我检测到唤醒时,我中止()帖子并开始另一个帖子。这在大多数情况下是有帮助的。但事实证明这是不可靠的。有时,时间事件似乎在睡眠期间保持正常滴答作响,但无论如何,发布请求都会被取消。而且它感觉不像是一个可靠的解决方案。
我正在使用最新版本的jQuery:(2.1.2)和Chrome(47)。
答:
我不确定这是否有效,我现在无法测试它,但试一试
$(window).focus(function() {
updater();
});
评论
我过去曾遇到过 JavaScript 调用在手机进入睡眠状态时被挂起的问题。我最终得到的解决方案是使用它似乎暂停,但当手机被唤醒时又恢复了生机。window.setInterval()
因此,我建议设置一个间隔,每隔一段时间取消一次呼叫并重新启动它。这可能有助于它在手机睡眠中生存。
大致如下:
var myCall = $.ajax({...});
Window.setInterval (refreshCall(), 10000);
function refreshCall (){
myCall.abort ();
myCall = $.ajax({...});
}
像这样更高级别的观察程序函数怎么样:
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();
});
您知道 $(window).focus 会在手机唤醒时触发,因此您可以按照 Almis 的建议尝试使用 updater(),但使用故障安全计时器。如果更新程序触发(在笔记本电脑或 iOS 上),计时器将被取消,一切正常,但如果更新程序已死,故障安全计时器将在 6 秒内触发,并通过调用 initializeAll() 重新启动整个应用程序。
存储调用时间,然后将上次调用的时间与当前时间进行比较怎么样 - 如果您的间隔是 10 秒,而自上次运行以来经过的时间是 5 分钟,您可以假设您刚刚从睡眠中醒来?然后中止当前的 ajax 调用,并重新启动它。setInterval
最好的答案是“不要那样做”。您让服务器在跟踪服务器端的更改时等待响应。只需让服务器响应并让 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);
评论