web-dev-qa-db-fra.com

Lorsque j'utilise setInterval, si je change d'onglet dans Chrome et que je reviens en arrière, le curseur devient fou en rattrapant

J'ai un curseur jQuery sur mon site et le code allant à la diapositive suivante est dans une fonction appelée nextImage. J'ai utilisé setInterval pour exécuter ma fonction sur un minuteur, et il fait exactement ce que je veux: il exécute mes diapositives sur un minuteur. MAIS, si je vais sur le site dans Chrome, basculer vers un autre onglet et revenir, le curseur parcourt les diapositives en continu jusqu'à ce qu'il "rattrape". Quelqu'un connaît-il un moyen de résoudre ce problème? Voici mon code.

setInterval(function() {
nextImage();
}, 8000);
45
Nathan Shubert

Comment détecter quand un onglet est focalisé ou non dans Chrome avec Javascript?

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

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

Pour postuler à 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 existe un bogue ou une "fonctionnalité" qui rend cela moins fiable, ce qui nécessite 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.

38
ninjagecko

Je poste une réponse ici: Comment puis-je faire en sorte que setInterval fonctionne également lorsqu'un onglet est inactif dans Chrome?

Faites ceci:

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

}, 1000);

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

La méthode window.setTimeout () s'interrompt désormais pour n'envoyer pas plus d'un timeout par seconde dans les onglets inactifs. En outre, il limite désormais les délais d'attente imbriqués à la plus petite valeur autorisée par la spécification HTML5: 4 ms (au lieu des 10 ms qu'il utilisait pour le verrouillage).

15
www

Quelques idées me viennent à l'esprit:


Idée n ° 1

Vous pouvez faire en sorte qu'une courte rafale soit idempotente . Par exemple, vous pourriez dire:

function now() {
    return (new Date()).getTime();
}

var autopagerInterval = 8000;

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

    var autopager = setInterval(
        function() {
            var timeSinceStart = now() - startTime();
            var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
            if (getCurrentImageNumber() != targetImage)
                setImageNumber(targetImage);  // trigger animation, etc.
        },
        autopagerInterval
    );
    return autopager;
}

De cette façon, même si la fonction s'exécute 1000 fois, elle ne s'exécutera qu'en quelques millisecondes et ne s'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'affiche originale veut, mais je laisse cette solution car c'est parfois ce que vous voulez.


Idée n ° 2

Une autre façon d'ajouter de l'idempotence (tout en conservant votre fonction nextImage() et en ne la faisant pas défiler vers le bas de la page) serait d'avoir la fonction définie un verrou mutex qui disparaît après une seconde (effacé par un autre timeout ). 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


Idée n ° 3

J'ai essayé le test suivant:

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

Cela semble indiquer que la fonction est appelée toutes les secondes. C'est étrange ... mais je pense que cela signifie que les rappels sont étant appelés, mais que le rendu de page refuse de mettre à jour la page de manière graphique tandis que l'onglet est flou, retardant toutes les opérations jusqu'au retour de l'utilisateur, mais les opérations continuent de s'accumuler.

De plus, la fonction window.focus() ne dit pas si la fenêtre a le focus; il DONNE le focus à la fenêtre, et n'est donc pas pertinent.

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 (flou), et réinitialisez-le lorsqu'il obtient la mise au point.

6
ninjagecko

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'image jQuery que j'ai créé, et je vivais la même chose que vous lorsque je suis passé à un onglet différent et vice-versa. Dans mon cas, la fonction animate () était mise en file d'attente, donc une fois la fenêtre retrouvée concentrée, le curseur deviendrait fou. Pour résoudre ce problème, j'ai juste arrêté la fonction animate () de la mise en file d'attente.

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

1
000justin000

J'avais rencontré un problème similaire, le 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
Maheshchandra Hegde

Si vous utilisez le curseur d'image de Soh Tanaka, ajoutez simplement ceci ... pour résoudre votre problème Google Chrome:

$(".image_reel").stop(true, true).fadeOut(300).animate({ left: -image_reelPosition}, 500 ).fadeIn(300);

Prenez note de la fonction .stop (). Ignorer le fondu entrant et sortant, c'est ce que j'ai utilisé sur ma version

Merci

0
Nasir