Что происходит с выполнением JavaScript (settimeout и т. Д.), Когда iPhone / Android переходит в режим сна? - PullRequest
36 голосов
/ 01 июля 2011

У меня есть мобильное веб-приложение jQuery, предназначенное для устройств iOS и Android. Компонентом приложения является фоновая задача, которая периодически проверяет наличие а) изменений локальных данных и б) подключение к серверу. Если оба значения верны, задача отправляет изменения.

Я использую простую функцию на основе setTimeout () для выполнения этой задачи. Каждое условие сбоя или успеха вызывает setTimeout () для фоновой задачи, гарантируя, что она выполняется с 30-секундными интервалами. Я обновляю статус div с помощью метки времени выполнения последней задачи для целей отладки.

В любом настольном браузере это работает просто отлично; однако на iOS или Android через некоторое время задача перестает выполняться. Мне интересно, связано ли это с настройками энергосбережения устройств - когда iOS переходит в режим ожидания, это прекращает выполнение JavaScript? Вот что, похоже, и происходит.

Если это так, каков наилучший способ возобновить? Есть ли событие, которое я могу подключить? Если нет, какие есть другие варианты, которые не включают в себя привязку к событиям, зависящим от взаимодействия с пользователем (я не хочу связывать всю страницу с событием щелчка, просто чтобы перезапустить фоновую задачу).

Ответы [ 4 ]

29 голосов
/ 01 июля 2011

Похоже, что выполнение Javascript приостановлено в MobileSafari, когда страница браузера не сфокусирована.Также кажется, что если события setInterval () запаздывают, они просто запускаются, как только браузер фокусируется.Это означает, что мы должны иметь возможность поддерживать setInterval () и предполагать, что браузер потерял / восстановил фокус, если функция setInterval заняла намного больше времени, чем обычно.

Этот код выдает предупреждение после переключения с вкладки браузера послепереключение обратно из другого приложения и после выхода из сна.Если вы установите порог немного дольше, чем setTimeout (), вы можете предположить, что ваш тайм-аут не закончится, если он сработает.

Если вы хотите остаться в безопасности: вы можете сохранить свой ID тайм-аута (возвращается через setTimeout) и установите для него более короткое пороговое значение, чем ваше время ожидания, затем снова запустите clearTimeout () и setTimeout (), если это произойдет.строка в резюме, так что вам нужно как-то с этим справиться.(После того, как мой Android-браузер спал всю ночь, он проснулся с двумя предупреждениями (). Бьюсь об заклад, Javascript был возобновлен в произвольное время перед тем, как полностью спать.)

Я тестировал на Android 2.2 и последней iOS -они оба предупреждают вас, как только вы возобновите сон.

4 голосов
/ 08 января 2015

Когда пользователь переключается на другое приложение или экран спит, кажется, что таймеры приостанавливаются до тех пор, пока пользователь не переключится обратно на приложение (или когда экран пробудится).

Phonegap имеет резюме событие, которое вы можете прослушивать вместо опроса состояния (а также событие пауза , если вы хотите сделать что-то до того, как оно не сфокусировано).Вы начинаете слушать его после срабатывания deviceReady.

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

Я использую angular с phonegap, и у меня реализована служба, которая управляет определенным тайм-аутом для меня, но в основном вы можете создать объект, который устанавливает таймер, отменяетtimer и, что наиболее важно, обновляет таймер (update - это то, что вызывается во время события возобновления).

В угловом режиме у меня есть области действия и корневая область, к которой я могу прикрепить данные, мое время ожидания глобально, поэтому яприкрепить его к корневой области, но для целей этого примера я просто прикреплю его к объекту документа.Я не потворствую этому, потому что вам нужно применить его к некоторой области видимости или пространству имен.

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

Вы захотите обновить таймер, как только вы получите событие возобновления в слушателе событий, например, так:

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

Менеджер тайм-аута также имеет cancelTimer(), который можно использовать для уничтожения таймера в любое время.

2 голосов
/ 12 июня 2016

Вы можете использовать этот класс github.com / mustafah / background-timer на основе ответа @jlafay, где вы можете использовать следующее:

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

Надеюсь, это поможет, спасибо ...

0 голосов
/ 05 июля 2019

Вы должны использовать API видимости страницы (MDN) , который поддерживается практически везде. Он может определить, стала ли страница или вкладка снова видимой, и затем вы можете возобновить время ожидания или выполнить некоторые действия.

...