45 votes

Lorsque j'utilise setInterval, si je bascule d'onglets dans Chrome et que je reviens, le curseur devient fou à rattraper

J'ai un curseur jQuery sur mon site et le code pour passer à la diapositive suivante se trouve dans une fonction appelée nextImage. J'ai utilisé setInterval pour exécuter ma fonction sur une minuterie, et cela fait exactement ce que je veux : il exécute mes diapositives sur une minuterie. MAIS, si je vais sur le site dans Chrome, basculez sur un autre onglet et revenez, le curseur parcourt les diapositives en continu jusqu'à ce qu'il "rattrape son retard". Quelqu'un sait-il comment résoudre ce problème. Voici mon code :

setInterval(function() {
nextImage();
}, 8000);

0 votes

Peut-être pouvez-vous ajouter une condition pour voir si la fenêtre est centrée avant d'exécuter la fonction nextImage()

0 votes

Désolé, comment cela se fait-il?

0 votes

Je viens de voir cela sur un forum mais je ne sais pas si cela fonctionne : (window.focus){nextImage();}

41voto

ninjagecko Points 25709

Comment détecter si un onglet est actif ou non dans Chrome avec Javascript?

window.addEventListener('focus', function() {
    document.title = 'actif';
},false);

window.addEventListener('blur', function() {
    document.title = 'non actif';
},false);

Pour appliquer à votre situation:

var autopager;
function startAutopager() {
    autopager = window.setInterval(nextImage, 8000);
}
function stopAutopager() {
    window.clearInterval(autopager);
}

window.addEventListener('focus', startAutopager);    
window.addEventListener('blur', stopAutopager);

Notez que dans la dernière version de Chromium, il y a soit un bug, soit une 'fonctionnalité' qui rend cela moins fiable, nécessitant que l'utilisateur ait cliqué au moins une fois n'importe où dans la fenêtre. Voir la question liée ci-dessus pour plus de détails.

0 votes

Voici une solution assez simple, mais je pense qu'un gestionnaire mousemove et touchmove serait plus adapté pour cela. Donc, s'il n'y a aucune activité à l'intérieur de l'onglet pendant un certain laps de temps, l'objet ne devrait pas recevoir le feu vert pour essayer d'exécuter quoi que ce soit.

1 votes

La réponse citée ici a été mise à jour et la solution donnée ne semble plus fonctionner, du moins pour moi. Ce qui a fonctionné est la réponse mise à jour à la question citée, qui consiste à utiliser l'événement visibilitychange comme ceci : document.addEventListener('visibilitychange', function(){ document.title = document.hidden; }). @ninjagecko pouvez-vous s'il vous plaît mettre à jour la réponse en conséquence?

16voto

www Points 753

Je poste une réponse ici: Comment puis-je faire fonctionner setInterval aussi lorsque un onglet est inactif dans Chrome?

Il suffit de faire ceci:

setInterval(function() {
    $("#your-image-container").stop(true,true);
    nextImage();

}, 1000);

Les onglets inactifs du navigateur conservent certains des événements setInterval ou setTimeout. stop(true,true) - arrêtera tous les événements mis en mémoire tampon et exécutera immédiatement seulement la dernière animation.

La méthode window.setTimeout() est maintenant limitée pour n'envoyer plus d'une temporisation par seconde dans les onglets inactifs. De plus, elle limite désormais les temporisations imbriquées à la plus petite valeur autorisée par la spécification HTML5: 4 ms (au lieu des 10 ms auxquels elle était auparavant limitée).

0 votes

Merci - J'ai cherché partout quelque chose qui puisse réparer cela et c'est ce qui a fonctionné.

6voto

ninjagecko Points 25709

Quelques idées viennent à l'esprit :


Idee n°1

Vous pouvez rendre une courte rafale idempotente. Par exemple, vous pourriez dire :

fonction maintenant() {
    return (nouvelle Date()).getTime();
}

var autopagerInterval = 8000;

function startAutopager() {
    var startImage = getCurrentImageNumber();
    var startTime = maintenant();

    var autopager = setInterval(
        function() {
            var timeSinceStart = maintenant() - startTime();
            var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
            if (getCurrentImageNumber() != targetImage)
                setImageNumber(targetImage);  // déclencher l'animation, etc.
        },
        autopagerInterval
    );
    return autopager;
}

Ainsi, même si la fonction s'exécute 1000 fois, elle s'exécutera toujours en seulement quelques millisecondes et n'animera qu'une seule fois.

note : Si l'utilisateur quitte la page et revient, elle aura défilé. Ce n'est probablement pas ce que l'auteur original veut, mais je laisse cette solution car c'est parfois ce que vous voulez.


Idee n°2

Une autre façon d'ajouter l'idempotence (tout en conservant votre fonction nextImage() et sans qu'elle ne défile jusqu'au bas de la page) serait de faire en sorte que la fonction définisse un verrou mutex qui disparaît après une seconde (effacé par un autre délai). Ainsi, même si la fonction setInterval était appelée 1000 fois, seule la première instance s'exécuterait et les autres ne feraient rien.

var locked = false;
var autopager = window.setInterval(function(){
    if (!locked) {
        locked = true;
        window.setTimeout(function(){
            locked=false;
        }, 1000);
        nextImage();
    }
}, 8000);

edit : cela peut ne pas fonctionner, voir ci-dessous


Idee n°3

J'ai essayé le test suivant :

function f() {
    console.log((new Date()) + window.focus());
    window.setTimeout(f, 1000);
}
f();

Il semble indiquer que la fonction est appelée toutes les secondes. C'est bizarre... mais je pense que cela signifie que les rappels sont bien appelés, mais que le rendu de la page refuse de se mettre à jour de quelque manière graphique que ce soit lorsque l'onglet est non focalisé, retardant toutes les opérations jusqu'au retour de l'utilisateur, mais les opérations continuent de s'empiler.

Aussi la fonction window.focus() ne dit pas si la fenêtre est au premier plan ; elle DONNE le focus à la fenêtre, et est donc sans pertinence.

Ce que nous voulons est probablement ceci : Comment détecter quand un onglet est focalisé ou non dans Chrome avec Javascript? -- vous pouvez annuler votre intervalle lorsque la fenêtre perd le focus (blur) et le réinitialiser lorsqu'elle le regagne.

0 votes

Où est-ce que j'appelle ma fonction nextImage avec cela?

0 votes

Vous auriez une fonction setImageNumber(num) au lieu de nextImage = function(){setImageNumber(getCurrentImageNumber()+1)}

0 votes

Si la solution if (!window.focus) fonctionne, elle est certainement supérieure à celle-ci, d'autant plus que je ne pense pas que vous ayez l'intention de demander à l'utilisateur de revenir en arrière et de constater que la page a défiler jusqu'en bas

1voto

000justin000 Points 11

Je ne sais pas exactement ce qui se passe dans votre fonction nextImage(), mais j'ai eu un problème similaire. J'utilisais animate() avec setInterval() sur un curseur d'images jQuery que j'ai créé, et j'éprouvais la même chose que vous lorsque je passais à un autre onglet puis revenais. Dans mon cas, la fonction animate() était mise en file d'attente, donc une fois que la fenêtre retrouvait le focus, le curseur devenait fou. Pour résoudre cela, j'ai simplement empêché la fonction animate() de se mettre en file d'attente.

Il existe plusieurs façons de le faire. Le plus simple est avec .stop(), mais ce problème et les façons de le résoudre sont documentés dans la documentation jQuery. Consultez cette page près du bas, sous le titre notes supplémentaires: http://api.jquery.com/animate/

0voto

J'avais rencontré un problème similaire, mais étrangement ce code ci-dessous fonctionne bien pour moi.

            var t1= window.setInterval('autoScroll()', 8000);

    window.addEventListener('focus', function() {
        focused = true;
        window.clearInterval(t1);
        t1 = window.setInterval('autoScroll()', 8000);
    },false);

    window.addEventListener('blur', function() {
        focused = false;
        window.clearInterval(t1);
    },false)

function autoScroll()

    {

        if ( running == true){
            if ( focused = true){
                forwardSlide();
            }

        }

        else {

            running = true;

        }

    }

0 votes

Vos valeurs de temporisation sont de 8000 ms, donc vous ne serez pas affecté par ce problème (aucune solution de contournement n'est nécessaire). Chrome permet à setInterval d'être appelé toutes les 1000 ms lorsque l'onglet n'a pas le focus.

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