C'è un modo per cancellare tutti i timeout da una determinata finestra? Suppongo che i timeout siano memorizzati da qualche parte window
nell'oggetto ma non ho potuto confermarlo.
Qualsiasi soluzione cross browser è la benvenuta.
C'è un modo per cancellare tutti i timeout da una determinata finestra? Suppongo che i timeout siano memorizzati da qualche parte window
nell'oggetto ma non ho potuto confermarlo.
Qualsiasi soluzione cross browser è la benvenuta.
Risposte:
Non sono nell'oggetto finestra, ma hanno id, che (afaik) sono numeri interi consecutivi.
Quindi puoi cancellare tutti i timeout in questo modo:
var id = window.setTimeout(function() {}, 0);
while (id--) {
window.clearTimeout(id); // will do nothing if no timeout with id is present
}
Penso che il modo più semplice per farlo sarebbe memorizzare tutti gli setTimeout
identificatori in un array, dove puoi facilmente iterare clearTimeout()
su tutti loro.
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]);
}
Ho un'aggiunta alla risposta di Pumbaa80 che potrebbe essere utile per qualcuno che sviluppa per i vecchi IE.
Sì, tutti i principali browser implementano gli ID di timeout come numeri interi consecutivi (che non è richiesto dalle specifiche ). Anche se il numero iniziale è diverso da browser a browser. Sembra che Opera, Safari, Chrome e IE> 8 avviino gli ID di timeout da 1, i browser basati su Gecko da 2 e IE <= 8 da un numero casuale che viene magicamente salvato nell'aggiornamento della scheda. Puoi scoprirlo da solo .
Tutto ciò significa che in IE <= 8 il while (lastTimeoutId--)
ciclo può essere eseguito più di 8 cifre e mostrare il messaggio " Uno script in questa pagina sta causando il rallentamento di Internet Explorer ". Quindi, se non è possibile salvare tutti gli ID timeout o non si desidera sovrascrivere window.setTimeout, è possibile considerare di salvare il primo ID timeout su una pagina e cancellare i timeout fino a quando non viene visualizzato.
Esegui il codice al caricamento iniziale della pagina:
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);
};
});
E poi cancella tutti i timeout in sospeso che probabilmente sono stati impostati da codice esterno tante volte che vuoi
Che ne dici di memorizzare gli id di timeout in un array globale e definire un metodo per delegare la chiamata alla funzione alla finestra.
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
}
};
Devi riscrivere il window.setTimeout
metodo e salvare il suo ID di timeout.
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();
}
}
Posiziona il codice seguente prima di qualsiasi altro script e creerà una funzione wrapper per l'originale setTimeout
& clearTimeout
.
Un nuovo clearTimeouts
metodo verrà aggiunto window
all'Oggetto, che consentirà di cancellare tutti i timeout (in sospeso) ( collegamento Gist ).
Altre risposte non supportano completamente i possibili argomenti che
setTimeout
potrebbero ricevere.
// 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);
Per completezza, volevo pubblicare una soluzione generale che copra sia setTimeout
e setInterval
.
Sembra che i browser potrebbero utilizzare lo stesso pool di ID per entrambi, ma da alcune delle risposte a ClearTimeout e clearInterval sono uguali? , non è chiaro se sia sicuro fare affidamento clearTimeout
e clearInterval
svolgere la stessa funzione o lavorare solo sui rispettivi tipi di timer.
Pertanto, quando l'obiettivo è eliminare tutti i timeout e gli intervalli, ecco un'implementazione che potrebbe essere leggermente più difensiva tra le implementazioni quando non è in grado di testarli tutti:
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(){}
}
Puoi usarlo per cancellare tutti i timer nella finestra corrente:
clearAll(window);
Oppure puoi usarlo per cancellare tutti i timer in un iframe
:
clearAll(document.querySelector("iframe").contentWindow);
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
}
}
Usa un timeout globale da cui derivano tutte le altre funzioni. Questo renderà tutto più veloce e sarà più facile da gestire, anche se aggiungerà un po 'di astrazione al tuo codice.
set_timeout
funzione globale? Potresti fornire un codice di esempio?
Abbiamo appena pubblicato un pacchetto che risolve esattamente questo problema.
npm install time-events-manager
Con ciò, puoi visualizzare tutti i timeout e gli intervalli tramite gli oggetti timeoutCollection
& intervalCollection
. C'è anche una removeAll
funzione che cancella tutti i timeout / intervalli sia dalla raccolta che dal browser.
È molto tardi ... ma:
Fondamentalmente, gli ID setTimeout / setInterval vanno in ordine consecutivo, quindi crea una funzione di timeout fittizia per ottenere l'ID più alto, quindi cancella l'intervallo su tutti gli ID inferiori a quello.
const highestId = window.setTimeout(() => {
for (let i = highestId; i >= 0; i--) {
window.clearInterval(i);
}
}, 0);