当iPhone / Android进入睡眠状态时,JavaScript执行(settimeout等)会发生什么?

时间:2011-07-01 03:36:28

标签: android ios web-applications mobile settimeout

我有一个针对iOS和Android设备的jQuery Mobile网络应用。应用程序的一个组件是后台任务,它定期检查a。)对本地数据的更改以及b。)与服务器的连接。如果两者都为真,则任务会推动更改。

我正在使用一个简单的基于setTimeout()的函数来执行此任务。每个失败或成功条件都会在后台任务上调用setTimeout(),确保它以30秒的间隔运行。我使用上一个任务运行时的时间戳更新状态div以进行调试。

在任何桌面浏览器中,这都可以正常工作;但是,在iOS或Android上,经过一段时间后,任务就会停止执行。我想知道这是否与设备的省电设置有关 - 当iOS进入待机状态时,是否会终止JavaScript执行?这似乎发生了。

如果是这样,恢复的最佳方式是什么?是否有可以挂钩的唤醒事件?如果没有,那么还有哪些其他选项不涉及依赖于用户交互的事件(我不想将整个页面绑定到单击事件只是为了重新启动后台任务)。

4 个答案:

答案 0 :(得分:29)

当浏览器页面没有聚焦时,看起来在MobileSafari上暂停了Javascript执行。似乎setInterval()事件迟到了,只要浏览器聚焦就会触发它们。这意味着我们应该能够保持setInterval()运行,并假设如果setInterval函数花费的时间比平时长得多,则浏览器会丢失/重新获得焦点。

此代码在从浏览器选项卡切换回来后,从另一个应用程序切换回来后,以及从睡眠状态恢复后发出警报。如果您将阈值设置为比setTimeout()稍长,则可以假设如果触发此超时将无法完成。

如果你想保持安全:你可以保存你的超时ID(由setTimeout返回)并将其设置为比你的超时更短的阈值,然后再次运行clearTimeout()和setTimeout()。 / p>

<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>

编辑:看起来这有时会在恢复时连续触发一次,所以你需要以某种方式处理它。 (让我的安卓浏览器彻夜难眠后,它醒来了两个alert()s。我打赌Javascript在完全睡眠之前的任意时间恢复了。)

我在Android 2.2和最新的iOS上测试过 - 一旦你从睡眠状态恢复,它们都会发出警报。

答案 1 :(得分:4)

当用户切换到另一个应用程序或屏幕休眠时,计时器似乎暂停,直到用户切换回应用程序(或屏幕唤醒)。

Phonegap有一个resume事件你可以听,而不是轮询状态(以及pause事件,如果你想在失焦前做事情)。在deviceReady触发后开始收听它。

document.addEventListener("deviceready", function () {
    // do something when the app awakens
    document.addEventListener('resume', function () {
        // re-create a timer.
        // ...
    }, false);
}, false);

我使用带有phonegap的角度,我实现了一个服务,为我管理一定的超时但基本上你可以创建一个设置定时器的对象,取消定时器,最重要的是,更新定时器(更新是在&#39;简历&#39;事件)。

在角度我有一个可以附加数据的范围和根范围,我的超时是全局的,所以我将它附加到根范围但是为了这个例子的目的,我只是将它附加到文档对象。我不会宽恕,因为你需要将它应用于某种范围或命名空间。

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;
            }
        }
    };
};

您可以让管理器函数采用毫秒参数而不是将其传递给集合,但在我编写的角度服务之后,这又是有点建模的。操作应该清晰简洁,以便与他们合作并将其添加到您自己的应用程序中。

var timeoutCallback = function () { console.log('timer fired!'); };
var manager = timeoutManager();
manager.setTimer(20000);

一旦在事件监听器中收到resume事件,您将需要更新计时器,如下所示:

// do something when the app awakens
document.addEventListener('resume', function () {
    var manager = timeoutManager();
    manager.updateTimer();
}, false);

超时管理器还有cancelTimer(),可用于随时终止计时器。

答案 2 :(得分:2)

您可以根据@jlafay答案使用此课程github.com/mustafah/background-timer,您可以按照以下方式使用:

的CoffeeScript

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();

希望它有所帮助,谢谢...

答案 3 :(得分:0)

您应该使用Page Visibility API (MDN),几乎所有地方都支持。它可以检测页面或标签是否再次变得可见,然后您可以继续超时或执行某些操作。