当 iPhone/Android 进入睡眠状态时,JavaScript 执行(settimeout 等)会发生啥?
Posted
技术标签:
【中文标题】当 iPhone/Android 进入睡眠状态时,JavaScript 执行(settimeout 等)会发生啥?【英文标题】:What happens to JavaScript execution (settimeout, etc.) when iPhone/Android goes to sleep?当 iPhone/Android 进入睡眠状态时,JavaScript 执行(settimeout 等)会发生什么? 【发布时间】:2011-09-26 11:09:25 【问题描述】:我有一个针对 ios 和 android 设备的 jQuery Mobile Web 应用程序。应用程序的一个组件是一个后台任务,它定期检查 a.) 本地数据的更改和 b.) 与服务器的连接。如果两者都为真,则任务推送更改。
我正在使用一个简单的基于 setTimeout() 的函数来执行此任务。每个失败或成功条件都会在后台任务上调用 setTimeout(),确保它以 30 秒的间隔运行。出于调试目的,我使用最后一个任务运行时的时间戳更新了一个状态 div。
在任何桌面浏览器中,这都可以正常工作;但是,在 iOS 或 Android 上,经过一段时间后,任务会停止执行。我想知道这是否与设备的节能设置有关-当iOS进入待机状态时,它会终止javascript执行吗?这似乎就是发生的事情。
如果是这样,最好的恢复方式是什么?是否有我可以加入的唤醒事件?如果没有,还有哪些其他选项不涉及挂钩依赖于用户交互的事件(我不想将整个页面绑定到单击事件以重新启动后台任务)。
【问题讨论】:
注意,苹果在 iOS8 中破坏了大部分问题,并且还没有修复它 - openradar.me/radar?id=5895945212395520 【参考方案1】:当浏览器页面未获得焦点时,MobileSafari 上的 Javascript 执行似乎已暂停。似乎如果 setInterval() 事件迟到了,只要浏览器聚焦,它们就会被触发。这意味着我们应该能够保持 setInterval() 运行,并假设如果 setInterval 函数花费的时间比平时长得多,浏览器会失去/重新获得焦点。
此代码会在从浏览器选项卡切换回来、从另一个应用切换回来以及从睡眠状态恢复后发出警报。如果你设置的阈值比你的 setTimeout() 长一点,你可以假设如果这个触发你的超时不会结束。
如果您想保持安全:您可以保存您的超时 ID(由 setTimeout 返回)并将其设置为比您的超时更短的阈值,然后在触发时再次运行 clearTimeout() 和 setTimeout()。
<script type="text/javascript">
var lastCheck = 0;
function sleepCheck()
var now = new Date().getTime();
var diff = now - lastCheck;
if (diff > 3000)
alert('took ' + diff + 'ms');
lastCheck = now;
window.onload = function()
lastCheck = new Date().getTime();
setInterval(sleepCheck, 1000);
</script>
编辑:看起来这有时会在简历中连续触发多次,因此您需要以某种方式处理它。 (让我的 android 浏览器睡一整夜后,它会唤醒两个 alert()。我敢打赌 Javascript 会在完全睡眠之前的某个任意时间恢复。)
我在 Android 2.2 和最新的 iOS 上进行了测试 - 一旦你从睡眠中恢复,它们都会发出警报。
【讨论】:
经过测试并且可以工作,但它会在某个时间点停止工作。就像一夜之间。安卓 5.1.1,铬。【参考方案2】:当用户切换到另一个应用或屏幕休眠时,计时器似乎会暂停,直到用户切换回应用(或屏幕唤醒时)。
Phonegap 有一个resume 事件,你可以收听而不是轮询状态(如果你想在它失去焦点之前做某事,还有一个pause 事件)。您在 deviceReady 触发后开始收听它。
document.addEventListener("deviceready", function ()
// do something when the app awakens
document.addEventListener('resume', function ()
// re-create a timer.
// ...
, false);
, false);
我将 Angular 与 phonegap 一起使用,并且我实现了一个服务,它为我管理一定的超时,但基本上你可以创建一个对象来设置计时器,取消计时器,最重要的是,更新计时器(更新是在'resume' 事件)。
在 Angular 中,我有一个范围和根范围,我可以将数据附加到,我的超时是全局的,所以我将它附加到根范围,但出于本示例的目的,我将简单地将它附加到文档对象。我不宽恕这种做法,因为您需要将其应用于某种范围或命名空间。
var timeoutManager = function ()
return
setTimer: function (expiresMsecs)
document.timerData =
timerId: setTimeout(function ()
timeoutCallback();
,
expiresMsecs),
totalDurationMsecs: expiresMsecs,
expirationDate: new Date(Date.now() += expiresMsecs)
;
,
updateTimer: function ()
if (document.timerData)
//
// Calculate the msecs remaining so it can be used to set a new timer.
//
var timerMsecs = document.timerData.expirationDate - new Date();
//
// Kill the previous timer because a new one needs to be set or the callback
// needs to be fired.
//
this.cancelTimer();
if (timerMsecs > 0)
this.setTimer(timerMsecs);
else
timeoutCallback();
,
cancelTimer: function ()
if (document.timerData && document.timerData.timerId)
clearTimeout(document.timerData.timerId);
document.timerData = null;
;
;
您可以让管理器函数接受一个毫秒参数,而不是将其传递给 set,但这又在某种程度上模仿了我编写的 Angular 服务。操作应该足够清晰和简洁,以便对它们进行一些操作并将它们添加到您自己的应用中。
var timeoutCallback = function () console.log('timer fired!'); ;
var manager = timeoutManager();
manager.setTimer(20000);
一旦在事件侦听器中获得恢复事件,您将需要更新计时器,如下所示:
// do something when the app awakens
document.addEventListener('resume', function ()
var manager = timeoutManager();
manager.updateTimer();
, false);
超时管理器还有cancelTimer()
,可以用来随时杀死定时器。
【讨论】:
如果它是开源的,您介意发布一个指向您的 Angular 服务的链接吗? @gabereal 对不起,我没有链接。它不是开源的。 好的。感谢您的答复。只是好奇。浏览器运行时是否只是暂停并从中断处继续? 恢复事件在 Safari 上不起作用 (developer.mozilla.org/en-US/docs/Web/Events/resume)【参考方案3】:你可以根据@jlafay answer使用这个类github.com/mustafah/background-timer,你可以使用如下:
咖啡脚本
timer = new BackgroundTimer 10 * 1000, ->
# This callback will be called after 10 seconds
console.log 'finished'
timer.enableTicking 1000, (remaining) ->
# This callback will get called every second (1000 millisecond) till the timer ends
console.log remaining
timer.start()
javascript
timer = new BackgroundTimer(10 * 1000, function()
// This callback will be called after 10 seconds
console.log("finished");
);
timer.enableTicking(1000, function(remaining)
// This callback will get called every second (1000 millisecond) till the timer ends
console.log(remaining);
);
timer.start();
希望对你有帮助,谢谢...
【讨论】:
它有效,谢谢。但它依赖于未提及的时刻.js 库。 这会监听github.com/mustafah/background-timer/blob/master/… Line 20 上的“resume”事件。但是“resume”事件在 Safari 上不起作用,因此它在 iOS 上不起作用。 developer.mozilla.org/en-US/docs/Web/Events/resume【参考方案4】:您应该使用几乎所有地方都支持的Page Visibility API (MDN)。它可以检测页面或选项卡是否再次可见,然后您可以恢复超时或执行一些操作。
【讨论】:
如果手机在页面上从锁定状态变为解锁状态,则不会触发页面可见性 API。仅当您从选项卡返回到应用程序选项卡或从最小化到最大化时,它才有效。我刚刚在 iOS Safari (iOS 13.7) 上进行了测试。以上是关于当 iPhone/Android 进入睡眠状态时,JavaScript 执行(settimeout 等)会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章