266 votes

Comment faire en sorte que setInterval fonctionne également lorsqu'un onglet est inactif dans Chrome?

J'ai un setInterval de l'exécution d'un morceau de code 30 fois par seconde. Cela fonctionne très bien, mais quand je suis sélectionnez un autre onglet (de sorte que la languette avec mon code devient inactif), l' setInterval est fixé à un état inactif pour une raison quelconque.

J'ai fait ce simplifié de cas de test (http://jsfiddle.net/7f6DX/3/):

var $div = $('div');
var a = 0;

setInterval(function() {
    a++;
    $div.css("left", a)
}, 1000 / 30);

Si vous exécutez ce code, et puis de passer à un autre onglet, attendre quelques secondes et revenir en arrière, l'animation continue au point où il était au moment de passer à l'autre onglet. Si l'animation n'est pas en cours d'exécution 30 fois par seconde dans le cas de l'onglet est inactif. Cela peut être confirmé par compter le nombre de fois que le setInterval fonction est appelée à chaque seconde - ce ne sera pas 30 mais juste 1 ou 2 si l'onglet est inactif.

Je suppose que c'est fait à dessein, de manière à améliorer les performances, mais est-il possible de désactiver ce comportement? Il est en fait un désavantage dans mon scénario.

183voto

cvsguimaraes Points 4327

Faites votre animation de la fonction tick par réel le temps écoulé.

http://jsfiddle.net/7f6DX/31/

var div = $('#my-div');
var leftValue = 0;
var interval = (1000/20); //20fps
var before = new Date();

setInterval(function()
{
    now = new Date();
    var elapsedTime = (now.getTime() - before.getTime());

    if(elapsedTime > interval)
    {
        //Recover the motion lost while inactive.
        leftValue += Math.floor(elapsedTime/interval);
    }
    else
    {
        leftValue++;
    }

    div.css("left", leftValue);
    before = new Date();    

}, interval);

MODIFIER

@UpTheCreek commentaire:

Amende pour la présentation des questions, mais encore il ya certaines choses que vous devez garder en cours d'exécution.

Pour cela, vous pouvez utiliser Web HTML5 Travailleurs. Jetez un oeil à Möhre de réponse...

NOTE

Compte tenu des animations, de ce problème et beaucoup d'autres sont résolus en utilisant les transitions CSS au lieu de jQuery fonctions d'animation. Je recommande ce plugin jQuery qui vous permet de bénéficier de l'CSS transitions comme l' animate() méthodes.

94voto

Möhre Points 151

J'ai rencontré le même problème avec le fading audio et le lecteur HTML5. Il s'est coincé quand l'onglet est devenu inactif. J'ai donc découvert qu'un WebWorker est autorisé à utiliser des intervalles / délais d'attente sans limitation. Je l'utilise pour poster des "ticks" sur le javascript principal.

Code WebWorkers:

 var fading = false;
var interval;
self.addEventListener('message', function(e){
    switch (e.data) {
        case 'start':
            if (!fading){
                fading = true;
                interval = setInterval(function(){
                    self.postMessage('tick');
                }, 50);
            }
            break;
        case 'stop':
            clearInterval(interval);
            fading = false;
            break;
    };
}, false);
 

Javascript principal:

 var player = new Audio();
player.fader = new Worker('js/fader.js');
player.faderPosition = 0.0;
player.faderTargetVolume = 1.0;
player.faderCallback = function(){};
player.fadeTo = function(volume, func){
    console.log('fadeTo called');
    if (func) this.faderCallback = func;
    this.faderTargetVolume = volume;
    this.fader.postMessage('start');
}
player.fader.addEventListener('message', function(e){
    console.log('fader tick');
    if (player.faderTargetVolume > player.volume){
        player.faderPosition -= 0.02;
    } else {
        player.faderPosition += 0.02;
    }
    var newVolume = Math.pow(player.faderPosition - 1, 2);
    if (newVolume > 0.999){
        player.volume = newVolume = 1.0;
        player.fader.postMessage('stop');
        player.faderCallback();
    } else if (newVolume < 0.001) {
        player.volume = newVolume = 0.0;
        player.fader.postMessage('stop');
        player.faderCallback();
    } else {
        player.volume = newVolume;
    }
});
 

14voto

www Points 753

Faites simplement ceci:

var $div = $('div');
var a = 0;

setInterval(function() {
    a++;
    $div.stop(true,true).css("left", a);
}, 1000 / 30);

Inactif onglets du navigateur tampon certains de l' setInterval ou setTimeout fonctions.

stop(true,true) arrêtera toutes tampon d'événements et de les exécuter immédiatement seule la dernière animation.

L' window.setTimeout() méthode maintenant pinces à ne pas envoyer plus d'un délai d'attente par seconde dans les onglets inactifs. En outre, il est désormais de pinces imbriquée délais d'attente à la plus petite valeur autorisée par la spécification HTML5: 4 ms (au lieu de 10 ms il a utilisé à la pince).

5voto

1st4ck Points 21

Je pense qu'une meilleure compréhension de ce problème est dans cet exemple: http://jsfiddle.net/TAHDb/

Je suis en train de faire une chose simple ici:

Avoir un intervalle de 1 seconde et chaque fois que de masquer la première travée et le déplacer vers la dernière, et montrer de la 2e travée.

Si vous restez sur la page il fonctionne comme il est censé. Mais si vous masquer l'onglet de quelques secondes, lorsque vous êtes de retour, vous verrez un weired chose.

Ses comme tous les événements qui n'ont pas ucur pendant le temps que vous avez été inactif maintenant apparaître selon les tous en 1 heure. donc, pour quelques secondes, vous obtiendrez comme X événements. ils sont si rapides qu'il est possible de voir tous les 6 couvre à la fois.

Donc il coutures chrome n'retards événements, de sorte que lorsque vous revenez tous les événements vont se produire, mais tout à la fois...

Une pratique de l'application ont été cette ocur iss pour un diaporama simple. Imaginez le nombre d'Images, et si l'utilisateur séjour avec onglet caché quand il revint, il va en voir de toutes les dhceu flottant, Totalement mesed.

Pour corriger cela, utilisez la fonction stop(true,true) comme pimvdb dit. Cela va vider la file d'attente des événements.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X