Czy istnieje sposób na wyczyszczenie wszystkich limitów czasu z danego okna? Przypuszczam, że limity czasu są przechowywane gdzieś w window
obiekcie, ale nie mogłem tego potwierdzić.
Mile widziane są dowolne rozwiązania dla różnych przeglądarek.
Czy istnieje sposób na wyczyszczenie wszystkich limitów czasu z danego okna? Przypuszczam, że limity czasu są przechowywane gdzieś w window
obiekcie, ale nie mogłem tego potwierdzić.
Mile widziane są dowolne rozwiązania dla różnych przeglądarek.
Odpowiedzi:
Nie ma ich w obiekcie window, ale mają identyfikatory, które (afaik) są kolejnymi liczbami całkowitymi.
Możesz więc wyczyścić wszystkie limity czasu w następujący sposób:
var id = window.setTimeout(function() {}, 0);
while (id--) {
window.clearTimeout(id); // will do nothing if no timeout with id is present
}
Myślę, że najłatwiejszym sposobem na osiągnięcie tego byłoby przechowywanie wszystkich setTimeout
identyfikatorów w jednej tablicy, w której można łatwo iterować clearTimeout()
na nich wszystkich.
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]);
}
Mam dodatek do odpowiedzi Pumba80, który może być przydatny dla kogoś, kto tworzy dla starych IE.
Tak, wszystkie główne przeglądarki implementują identyfikatory limitów czasu jako kolejne liczby całkowite (co nie jest wymagane przez specyfikację ). Chociaż numer początkowy różni się od przeglądarki do przeglądarki. Wygląda na to, że Opera, Safari, Chrome i IE> 8 uruchamia identyfikatory limitów czasu z 1, przeglądarki oparte na Gecko z 2 i IE <= 8 z jakiejś losowej liczby, która jest magicznie zapisywana podczas odświeżania karty. Możesz sam to odkryć .
Wszystko to oznacza, że w IE <= 8 while (lastTimeoutId--)
cykl może trwać ponad 8 cyfr razy i wyświetlać komunikat „ Skrypt na tej stronie powoduje powolne działanie przeglądarki Internet Explorer ”. Więc jeśli nie możesz zapisać wszystkich swoich timeout id lub nie chcesz nadpisywać window.setTimeout , możesz rozważyć zapisanie pierwszego timeout id na stronie i wyczyszczenie timeoutów do tego czasu.
Wykonaj kod przy wczesnym ładowaniu strony:
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);
};
});
A następnie wyczyść wszystkie oczekujące limity czasu, które prawdopodobnie zostały ustawione przez obcy kod tyle razy, ile chcesz
Co powiesz na przechowywanie identyfikatorów limitów czasu w tablicy globalnej i zdefiniowanie metody delegowania wywołania funkcji do okna.
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
}
};
Musisz przepisać window.setTimeout
metodę i zapisać jej identyfikator limitu czasu.
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();
}
}
Umieść poniższy kod przed jakimkolwiek innym skryptem, a utworzy on funkcję opakowującą dla oryginalnego setTimeout
& clearTimeout
.
clearTimeouts
Do window
obiektu zostaną dodane nowe metody , które pozwolą na wyczyszczenie wszystkich (oczekujących) limitów czasu ( łącze Gist ).
W innych odpowiedziach brakuje pełnego poparcia dla możliwych argumentów
setTimeout
.
// 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);
Dla kompletności chciałem zamieścić ogólne rozwiązanie, które obejmuje zarówno setTimeout
i setInterval
.
Wygląda na to, że przeglądarki mogą używać tej samej puli identyfikatorów w obu przypadkach, ale z niektórych odpowiedzi na pytanie Czy clearTimeout i clearInterval są takie same? , nie jest jasne, czy można bezpiecznie polegać clearTimeout
i clearInterval
wykonywać tę samą funkcję, czy też pracować tylko na odpowiednich typach timerów.
Dlatego, gdy celem jest zabicie wszystkich limitów czasu i interwałów, oto implementacja, która może być nieco bardziej defensywna we wszystkich implementacjach, gdy nie można przetestować ich wszystkich:
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(){}
}
Możesz go użyć do wyczyszczenia wszystkich timerów w bieżącym oknie:
clearAll(window);
Lub możesz go użyć do wyczyszczenia wszystkich timerów w iframe
:
clearAll(document.querySelector("iframe").contentWindow);
Używam Vue z Typescriptem.
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
}
}
Użyj globalnego limitu czasu, z którego pochodzą wszystkie inne funkcje. Dzięki temu wszystko będzie działać szybciej i będzie łatwiejsze w zarządzaniu, chociaż doda trochę abstrakcji do twojego kodu.
set_timeout
funkcji globalnej? Czy mógłbyś podać przykładowy kod?
Właśnie opublikowaliśmy pakiet rozwiązujący dokładnie ten problem.
npm install time-events-manager
Dzięki temu możesz przeglądać wszystkie limity czasu i interwały za pośrednictwem timeoutCollection
& intervalCollection
obiektów. Istnieje również removeAll
funkcja, która usuwa wszystkie limity czasu / interwały zarówno z kolekcji, jak i przeglądarki.
Jest już bardzo późno ... ale:
Zasadniczo identyfikatory setTimeout / setInterval idą w kolejności, więc po prostu utwórz fikcyjną funkcję limitu czasu, aby uzyskać najwyższy identyfikator, a następnie wyczyść interwał dla wszystkich identyfikatorów niższych od tego.
const highestId = window.setTimeout(() => {
for (let i = highestId; i >= 0; i--) {
window.clearInterval(i);
}
}, 0);