javascript: Effacer tous les délais?

99

Existe-t-il un moyen d'effacer tous les temps morts d'une fenêtre donnée? Je suppose que les délais d'attente sont stockés quelque part dans l' windowobjet, mais je n'ai pas pu le confirmer.

Toute solution multi-navigateurs est la bienvenue.

marcio
la source
6
Mec, cette question date d'il y a 3 ans et contient d'excellentes réponses. Pas besoin de jouer avec ça.
marcio
J'ai cherché ceci et j'ai trouvé les deux. Le vôtre était plus âgé, alors j'ai pensé qu'il serait judicieux de réduire les deux questions à une. Le mien est juste un vote; un certain nombre de personnes supplémentaires devront voter pour fermer, et le lien en double pourrait aider les autres.
Bernhard Hofmann
2
@Bernard Hofmann Je ne sais pas si cela compte comme une question en double si celle-ci a une meilleure réponse. La réponse acceptée sur celle-là de 2010 était "Non".
RoboticRenaissance

Réponses:

148

Ils ne sont pas dans l'objet window, mais ils ont des identifiants, qui (afaik) sont des entiers consécutifs.

Vous pouvez donc effacer tous les délais comme suit:

var id = window.setTimeout(function() {}, 0);

while (id--) {
    window.clearTimeout(id); // will do nothing if no timeout with id is present
}
user123444555621
la source
1
Cela fait-il partie de la spécification ou pourrait-il dépendre de l'implémentation?
Tikhon Jelvis
7
Il n'est pas nécessaire qu'il commence à 1. La spécification HTML5 dit "Soit handle un entier défini par l'agent utilisateur qui est supérieur à zéro qui identifiera le délai d'expiration à définir par cet appel." ce qui laisse de la place pour que le handle soit un entier positif comprenant des entiers non consécutifs et non petits.
Mike Samuel
3
C'est très intelligent, mais l'OP devrait probablement demander s'il existe une meilleure solution qui garde la trace des minuteries actives.
Jason Harwig le
3
N'est-ce pas une boucle infinie? Tous les navigateurs ne rendent pas if (0) comme faux.
Travis J
2
Depuis que j'ai demandé comment effacer TOUS les délais d'attente, j'accepte cette réponse. Solution très intelligente.
marcio
79

Je pense que le moyen le plus simple d'y parvenir serait de stocker tous les setTimeoutidentifiants dans un seul tableau, où vous pouvez facilement les parcourir clearTimeout()sur chacun d'eux.

var timeouts = [];
timeouts.push(setTimeout(function(){alert(1);}, 200));
timeouts.push(setTimeout(function(){alert(2);}, 300));
timeouts.push(setTimeout(function(){alert(3);}, 400));

for (var i=0; i<timeouts.length; i++) {
  clearTimeout(timeouts[i]);
}
Michael Berkowski
la source
14
Cela a l'avantage (ou l'inconvénient potentiel, je suppose) de ne supprimer que ceux que vous avez définis, de sorte que vous ne casserez pas par inadvertance le code extérieur.
Tikhon Jelvis le
1
+1,
n'effacera
1
C'est la meilleure solution car elle ne cassera pas le code externe, mais comme j'ai demandé comment effacer tous les délais, j'ai fini par accepter la réponse @ Pumbaa80 :)
marcio
2
@marcioAlmada Étrange, mais cool de vous voir revenir pour commenter à nouveau 2,5 ans plus tard :)
Michael Berkowski
6
J'aimerais peut-être effacer tous les délais et intervalles lorsque j'entre dans une page Web que je ne contrôle pas, car ils ont une annonce pop-up ennuyeuse qui ne démarre qu'après l'exécution de mon adblocker.
RoboticRenaissance
12

J'ai un ajout à la réponse de Pumbaa80 qui pourrait être utile pour quelqu'un qui développe pour d'anciens IE.

Oui, tous les principaux navigateurs implémentent les identifiants de délai d'expiration sous forme d'entiers consécutifs (ce qui n'est pas requis par la spécification ). Bien que le numéro de départ diffère d'un navigateur à l'autre. Il semble qu'Opera, Safari, Chrome et IE> 8 démarre les identifiants de délai d'expiration à partir de 1, les navigateurs basés sur Gecko à partir de 2 et IE <= 8 à partir d'un nombre aléatoire enregistré comme par magie lors de l'actualisation de l'onglet. Vous pouvez le découvrir vous-même .

Tout cela signifie que dans IE <= 8, le while (lastTimeoutId--)cycle peut s'exécuter plus de 8 chiffres et afficher le message « Un script sur cette page provoque l'exécution lente d'Internet Explorer ». Donc, si vous ne pouvez pas enregistrer tous vos identifiants de délai d'expiration ou si vous ne voulez pas remplacer window.setTimeout, vous pouvez envisager d'enregistrer le premier identifiant d'expiration sur une page et de supprimer les délais d'attente jusqu'à ce qu'il.

Exécutez le code au début du chargement de la page:

var clearAllTimeouts = (function () {
    var noop = function () {},
        firstId = window.setTimeout(noop, 0);
    return function () {
        var lastId = window.setTimeout(noop, 0);
        console.log('Removing', lastId - firstId, 'timeout handlers');
        while (firstId != lastId)
            window.clearTimeout(++firstId);
    };
});

Et puis effacez tous les délais d'attente qui ont probablement été définis par un code étranger tant de fois que vous le souhaitez

Kolya Ay
la source
plus un pour clarifier des informations plus détaillées.
Sanjay
8

Que diriez-vous de stocker les identifiants de délai d'expiration dans un tableau global et de définir une méthode pour déléguer l'appel de fonction à la fenêtre.

GLOBAL={
    timeouts : [],//global timeout id arrays
    setTimeout : function(code,number){
        this.timeouts.push(setTimeout(code,number));
    },
    clearAllTimeout :function(){
        for (var i=0; i<this.timeouts.length; i++) {
            window.clearTimeout(this.timeouts[i]); // clear all the timeouts
        }
        this.timeouts= [];//empty the id array
    }
};
Jaskey
la source
3

Vous devez réécrire la window.setTimeoutméthode et enregistrer son ID de délai d'expiration.

const timeouts = [];
const originalTimeoutFn = window.setTimeout;

window.setTimeout = function(fun, delay) { //this is over-writing the original method
  const t = originalTimeoutFn(fn, delay);
  timeouts.push(t);
}

function clearTimeouts(){
  while(timeouts.length){
    clearTimeout(timeouts.pop();
  }
}
client
la source
3

Pour effacer tous les délais d' attente , ils doivent être « capturés » premier :

Placez le code ci-dessous avant tout autre script et cela créera une fonction wrapper pour l'original setTimeout&clearTimeout .

Une nouvelle clearTimeoutsméthode sera ajoutée à l' windowobjet, ce qui permettra d'effacer tous les délais (en attente) ( lien Gist ).

D'autres réponses manquent de support complet pour d'éventuels arguments setTimeout pourraient recevoir.

// isolated layer wrapper (for the local variables)
(function(_W){

var cache = [],                // will store all timeouts IDs
    _set = _W.setTimeout,      // save original reference
    _clear = _W.clearTimeout  // save original reference

// Wrap original setTimeout with a function 
_W.setTimeout = function( CB, duration, arg ){
    // also, wrap the callback, so the cache reference will be removed 
    // when the timeout has reached (fired the callback)
    var id = _set(function(){
        CB.apply(null, arguments)
        removeCacheItem(id)
    }, duration || 0, arg)

    cache.push( id ) // store reference in the cache array

    // id reference must be returned to be able to clear it 
    return id
}

// Wrap original clearTimeout with a function 
_W.clearTimeout = function( id ){
    _clear(id)
    removeCacheItem(id)
}

// Add a custom function named "clearTimeouts" to the "window" object
_W.clearTimeouts = function(){
    console.log("Clearing " + cache.length + " timeouts")
    cache.forEach(n => _clear(n))
    cache.length = []
}

// removes a specific id from the cache array 
function removeCacheItem( id ){
    var idx = cache.indexOf(id)

    if( idx > -1 )
        cache = cache.filter(n => n != id )
}

})(window);
vsync
la source
2

Par souci d'exhaustivité, je souhaitais publier une solution générale couvrant à la fois setTimeoutet setInterval.

Il semble que les navigateurs puissent utiliser le même pool d'identifiants pour les deux, mais à partir de certaines réponses à ClearTimeout et clearInterval sont-elles identiques? , il n'est pas clair s'il est sûr de se fier clearTimeoutetclearInterval exécuter la même fonction ou de ne travailler que sur leurs types de minuterie respectifs.

Par conséquent, lorsque l'objectif est de supprimer tous les délais et intervalles, voici une implémentation qui pourrait être légèrement plus défensive entre les implémentations lorsqu'elle ne peut pas toutes les tester:

function clearAll(windowObject) {
  var id = Math.max(
    windowObject.setInterval(noop, 1000),
    windowObject.setTimeout(noop, 1000)
  );

  while (id--) {
    windowObject.clearTimeout(id);
    windowObject.clearInterval(id);
  }

  function noop(){}
}

Vous pouvez l'utiliser pour effacer tous les minuteurs de la fenêtre actuelle:

clearAll(window);

Ou vous pouvez l'utiliser pour effacer tous les minuteurs dans un iframe:

clearAll(document.querySelector("iframe").contentWindow);
Chris Calo
la source
gardez à l'esprit que cette approche détruit l'observateur de vue-cli-service, vous ne pouvez donc pas effectuer de rechargement à chaud lors du nettoyage de tous les délais et intervalles de temps. Je suppose que c'est la même chose pour d'autres observateurs de rechargement à chaud pour des frameworks tels que (angular, react, braise, etc.)
Michail Michailidis
1

J'utilise Vue avec Typescript.

    private setTimeoutN;
    private setTimeoutS = [];

    public myTimeoutStart() {

        this.myTimeoutStop();//stop All my timeouts

        this.setTimeoutN = window.setTimeout( () => {
            console.log('setTimeout');
        }, 2000);

        this.setTimeoutS.push(this.setTimeoutN)//add THIS timeout ID in array

    }

    public myTimeoutStop() {

        if( this.setTimeoutS.length > 0 ) {
            for (let id in this.setTimeoutS) {
                console.log(this.setTimeoutS[id]);
                clearTimeout(this.setTimeoutS[id]);
            }
            this.setTimeoutS = [];//clear IDs array
        }
    }
LuanLuanLuan
la source
0

Utilisez un délai d'expiration global dont toutes vos autres fonctions dérivent la synchronisation. Cela rendra tout plus rapide et plus facile à gérer, même si cela ajoutera une certaine abstraction à votre code.

Travis J
la source
Je ne te comprends pas complètement. Vous voulez étendre le comportement de la set_timeoutfonction globale? Pouvez-vous donner un exemple de code?
marcio
1
Je voulais simplement dire que vous avez un délai d'attente global qui s'exécute une fois toutes les 50 ms. Toute autre fonction qui nécessiterait un élément de minutage le récupérerait alors dans le délai d'expiration global. Google est passé à cela pour plus d'efficacité, même si je ne trouve plus l'article le citant.
Travis J
0

Nous venons de publier un package résolvant exactement ce problème.

npm install time-events-manager

Avec cela, vous pouvez afficher tous les délais et intervalles via timeoutCollection& intervalCollectionobjets. Il existe également une removeAllfonction qui efface tous les délais / intervalles à la fois de la collection et du navigateur.

Bar Goldinfeld
la source
0

C'est très tard ... mais:

Fondamentalement, les ID setTimeout / setInterval vont dans un ordre consécutif, il suffit donc de créer une fonction de temporisation fictive pour obtenir l'ID le plus élevé, puis d'effacer l'intervalle sur tous les ID inférieurs.

const highestId = window.setTimeout(() => {
  for (let i = highestId; i >= 0; i--) {
    window.clearInterval(i);
  }
}, 0);
charri
la source