web-dev-qa-db-fra.com

Comment arrêter une boucle setTimeout?

J'essaie de construire un indicateur de chargement avec une image Sprite et je suis venu avec cette fonction

function setBgPosition() {
   var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
       Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<numbers.length)
        {
            setTimeout(run, 200);
        }else
        {
            setBgPosition();
        }
    }
    setTimeout(run, 200);
}

de sorte que la sortie est ressemble à ceci

http://jsfiddle.net/TTkre/

Je devais utiliser setBgPosition (); à l’intérieur d’autre chose pour que cela continue dans une boucle, alors maintenant, mon problème est de savoir comment arrêter cette boucle quand je veux [chargement terminé]

47
Gihan Lasita

setTimeout renvoie un descripteur de minuterie, que vous pouvez utiliser pour arrêter le délai avec clearTimeout.

Donc par exemple:

function setBgPosition() {
    var c = 0,
        timer = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c >= numbers.length) {
            c = 0;
        }
        timer = setTimeout(run, 200);
    }
    timer = setTimeout(run, 200);

    return stop;

    function stop() {
        if (timer) {
            clearTimeout(timer);
            timer = 0;
        }
}

Donc, vous utiliseriez cela comme:

var stop = setBgPosition();
// ...later, when you're ready to stop...
stop();

Notez que plutôt que d'avoir setBgPosition à appeler de nouveau lui-même, je viens juste de le redéfinir à c sur 0. Sinon, ça ne marcherait pas. Notez également que j'ai utilisé 0 en tant que valeur de descripteur lorsque le délai d'attente n'est pas en attente. 0 n'est pas une valeur de retour valide de setTimeout et constitue donc un indicateur pratique.

C’est aussi l’un des (rares) endroits où je pense qu’il serait préférable d’utiliser setInterval plutôt que setTimeout. setInterval répète. Alors:

function setBgPosition() {
    var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c >= numbers.length) {
            c = 0;
        }
    }
    return setInterval(run, 200);
}

Utilisé comme ceci:

var timer = setBgPosition();
// ...later, when you're ready to stop...
clearInterval(timer);

En dépit de tout ce qui précède, j'aimerais trouver un moyen de rendre setBgPosition arrêter les choses lui-même , en détectant qu'une condition d'achèvement a été remplie.

77
T.J. Crowder

Je sais que c'est une vieille question, j'aimerais quand même poster mon approche. De cette façon, vous n'avez pas à gérer le truc 0 que T. J. Crowder a expliqué.

var keepGoing = true;

function myLoop() {
    // ... Do something ...

    if(keepGoing) {
        setTimeout(myLoop, 1000);
    }
}

function startLoop() {
    keepGoing = true;
    myLoop();
}

function stopLoop() {
    keepGoing = false;
}
9
ThimoKl

Vous devez utiliser une variable pour suivre le "rendu", puis la tester à chaque itération de la boucle. Si c'est fait == vrai, alors retourne.

var done = false;

function setBgPosition() {
    if ( done ) return;
    var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
        if ( done ) return;
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<numbers.length)
        {
            setTimeout(run, 200);
        }else
        {
            setBgPosition();
        }
    }
    setTimeout(run, 200);
}

setBgPosition(); // start the loop

setTimeout( function(){ done = true; }, 5000 ); // external event to stop loop
2
Neil Essy

LA MANIÈRE LA PLUS SIMPLE DE GÉRER LA BOUCLE TIMEOUT

function myFunc (terminator = false) {
    if(terminator) {
        clearTimeout(timeOutVar);
    } else {
        // do something
        timeOutVar = setTimeout(function(){myFunc();}, 1000);
    }
}   
myFunc(true); //  -> start loop
myFunc(false); //  -> end loop
2
VALIKHAN

Comme ceci est étiqueté avec la balise extjs, il peut être intéressant de regarder la méthode extjs: http://docs.sencha.com/extjs/6.2.0/classic/Ext.Function.html#method-interval

Cela fonctionne beaucoup comme setInterval, mais prend également en charge la portée, et permet également de transmettre des arguments:

function setBgPosition() {
    var c = 0;
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run() {
       Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<numbers.length){
            c=0;
        }
    }
    return Ext.Function.interval(run,200);
}

var bgPositionTimer = setBgPosition();

quand vous voulez arrêter, vous pouvez utiliser clearInterval pour l'arrêter

clearInterval(bgPositionTimer);

Un exemple de cas d'utilisation serait:

Ext.Ajax.request({
    url: 'example.json',

    success: function(response, opts) {
        clearInterval(bgPositionTimer);
    },

    failure: function(response, opts) {
        console.log('server-side failure with status code ' + response.status);
        clearInterval(bgPositionTimer);
    }
});
1
Theo

Je ne suis pas sûr, mais c'est peut-être ce que vous voulez:

var c = 0;
function setBgPosition()
{
    var numbers = [0, -120, -240, -360, -480, -600, -720];
    function run()
    {
        Ext.get('common-spinner').setStyle('background-position', numbers[c++] + 'px 0px');
        if (c<=numbers.length)
        {
            setTimeout(run, 200);
        }
        else
        {
            Ext.get('common-spinner').setStyle('background-position', numbers[0] + 'px 0px');
        }
    }
    setTimeout(run, 200);
}
setBgPosition();
0
Pritom