javascript: ¿Borrar todos los tiempos de espera?

99

¿Hay alguna forma de borrar todos los tiempos de espera de una ventana determinada? Supongo que los tiempos de espera se almacenan en algún lugar del windowobjeto, pero no puedo confirmarlo.

Cualquier solución de navegador cruzado es bienvenida.

marcio
fuente
6
Amigo, esta pregunta es de hace 3 años y tiene excelentes respuestas. No hay necesidad de meterse con eso.
marcio
Busqué esto y encontré ambos. El tuyo era mayor, así que pensé que sería una buena limpieza reducir las dos preguntas a una. El mío es solo un voto; Unas cuantas personas más necesitarán votar para cerrar, y el enlace duplicado podría ayudar a otros.
Bernhard Hofmann
2
@Bernard Hofmann No estoy seguro de si cuenta como una pregunta duplicada si esta obtuvo una mejor respuesta. La respuesta aceptada sobre eso de 2010 fue "No".
RoboticRenaissance

Respuestas:

148

No están en el objeto de ventana, pero tienen identificadores, que (afaik) son enteros consecutivos.

Por lo tanto, puede borrar todos los tiempos de espera de esta manera:

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

while (id--) {
    window.clearTimeout(id); // will do nothing if no timeout with id is present
}
usuario123444555621
fuente
1
¿Es esto parte de la especificación o podría depender de la implementación?
Tikhon Jelvis
7
No es necesario que comience en 1. La especificación HTML5 dice "Sea handle un número entero definido por el usuario-agente mayor que cero que identificará el tiempo de espera que se establecerá en esta llamada". lo que deja espacio para que el identificador sea cualquier número entero positivo, incluidos los números enteros no consecutivos y no pequeños.
Mike Samuel
3
Eso es muy inteligente, pero el OP probablemente debería preguntar si hay una mejor solución que realice un seguimiento de los temporizadores activos.
Jason Harwig
3
¿No es este un bucle infinito? No todos los navegadores muestran si (0) como falso.
Travis J
2
Como pregunté cómo borrar TODOS los tiempos de espera, acepto esta respuesta. Solución muy inteligente.
marcio
79

Creo que la forma más fácil de lograr esto sería almacenar todos los setTimeoutidentificadores en una matriz, donde puede iterar fácilmente clearTimeout()en todos ellos.

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
fuente
14
Esto tiene la ventaja (o el posible inconveniente, supongo) de borrar solo los que establezca, por lo que no romperá el código externo sin darse cuenta.
Tikhon Jelvis
1
+1, no borrará todos los tiempos de espera, pero es una buena solución para borrar un grupo específico de tiempos de espera a la vez
marcio
1
Esta es la mejor solución porque no romperá el código externo, pero como pregunté cómo borrar todos los tiempos de espera terminé aceptando la respuesta de @ Pumbaa80 :)
marcio
2
@marcioAlmada Extraño, pero genial verte volver a comentar sobre esto de nuevo 2.5 años después :)
Michael Berkowski
6
Quizás me gustaría borrar todos los tiempos de espera e intervalos cuando entro en una página web que no controlo, porque tienen un anuncio emergente molesto que no comienza hasta que se ejecuta mi bloqueador de anuncios.
RoboticRenaissance
12

Tengo una adición a la respuesta de Pumbaa80 que podría ser útil para alguien que esté desarrollando para IEs antiguas.

Sí, todos los navegadores principales implementan identificadores de tiempo de espera como enteros consecutivos (lo cual no es requerido por la especificación ). Aunque el número inicial difiere de un navegador a otro. Parece que Opera, Safari, Chrome e IE> 8 inician identificadores de tiempo de espera de 1, navegadores basados ​​en Gecko de 2 e IE <= 8 de algún número aleatorio que se guarda mágicamente en la actualización de pestañas. Puedes descubrirlo tú mismo .

Todo eso significa que en IE <= 8 el while (lastTimeoutId--)ciclo puede correr más de 8 dígitos y mostrar el mensaje " Un script en esta página hace que Internet Explorer se ejecute lentamente ". Entonces, si no puede guardar todos sus identificadores de tiempo de espera o no desea anular window.setTimeout , puede considerar guardar el primer identificador de tiempo de espera en una página y borrar los tiempos de espera hasta ese momento.

Ejecute el código en la carga de la página inicial:

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);
    };
});

Y luego borre todos los tiempos de espera pendientes que probablemente fueron establecidos por código externo tantas veces como desee

Kolya Ay
fuente
más uno para aclarar información más detallada.
Sanjay
8

¿Qué tal almacenar los identificadores de tiempo de espera en una matriz global y definir un método para delegar la llamada de función a la ventana.

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
fuente
3

Tienes que reescribir el window.setTimeoutmétodo y guardar su ID de tiempo de espera.

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();
  }
}
invitado
fuente
3

Para borrar todos los tiempos de espera , primero deben "capturarse" :

Coloque el siguiente código antes de cualquier otro script y creará una función contenedora para el setTimeout& original clearTimeout.

Se clearTimeoutsagregarán nuevos métodos al windowObjeto, que permitirán borrar todos los tiempos de espera (pendientes) ( enlace Gist ).

Otras respuestas carecen de soporte completo para los posibles argumentos que setTimeout puedan recibir.

// 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
fuente
2

Para completar, quería publicar una solución general que cubra tanto setTimeouty setInterval.

Parece que los navegadores pueden usar el mismo grupo de ID para ambos, pero de algunas de las respuestas a ¿Son clearTimeout y clearInterval iguales? , no está claro si es seguro confiar clearTimeouty clearIntervalrealizar la misma función o solo trabajar en sus respectivos tipos de temporizador.

Por lo tanto, cuando el objetivo es eliminar todos los tiempos de espera e intervalos, aquí hay una implementación que podría ser un poco más defensiva en todas las implementaciones cuando no se pueden probar todas:

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(){}
}

Puede usarlo para borrar todos los temporizadores en la ventana actual:

clearAll(window);

O puede usarlo para borrar todos los temporizadores en un iframe:

clearAll(document.querySelector("iframe").contentWindow);
Chris Calo
fuente
Tenga en cuenta que este enfoque destruye vue-cli-service watcher, por lo que no puede realizar una recarga en caliente al limpiar todos los tiempos de espera e intervalos de tiempo. Supongo que es lo mismo para otros observadores de recarga en caliente para marcos como (angular, react, ember, etc.)
Michail Michailidis
1

Yo uso Vue con 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
fuente
0

Utilice un tiempo de espera global del que derivan todas sus otras funciones. Esto hará que todo se ejecute más rápido y sea más fácil de administrar, aunque agregará algo de abstracción a su código.

Travis J
fuente
No te entiendo del todo. ¿Quiere ampliar el comportamiento de la set_timeoutfunción global? ¿Podría darnos un código de ejemplo?
marcio
1
Solo quise decir que tiene un tiempo de espera global que se ejecuta una vez cada 50 ms. Cualquier otra función que requiera un elemento de tiempo lo tomará del tiempo de espera global. Google cambió a esto por eficiencia, aunque ya no puedo encontrar el artículo que lo cita.
Travis J
0

Acabamos de publicar un paquete que resuelve este problema exacto.

npm install time-events-manager

Con eso, puede ver todos los tiempos de espera e intervalos a través de timeoutCollection& intervalCollectionobjetos. También hay una removeAllfunción que borra todos los tiempos de espera / intervalos tanto de la colección como del navegador.

Bar Goldinfeld
fuente
0

Esto es muy tarde ... pero:

Básicamente, los ID de setTimeout / setInterval van en orden consecutivo, así que simplemente cree una función de tiempo de espera ficticio para obtener el ID más alto, luego borre el intervalo en todos los ID inferiores a ese.

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