Есть ли способ очистить все тайм-ауты из данного окна? Я полагаю, что таймауты хранятся где-то в window
объекте, но не могу это подтвердить.
Приветствуется любое кроссбраузерное решение.
Есть ли способ очистить все тайм-ауты из данного окна? Я полагаю, что таймауты хранятся где-то в window
объекте, но не могу это подтвердить.
Приветствуется любое кроссбраузерное решение.
Ответы:
Их нет в объекте окна, но у них есть идентификаторы, которые (afaik) являются последовательными целыми числами.
Таким образом, вы можете очистить все таймауты следующим образом:
var id = window.setTimeout(function() {}, 0);
while (id--) {
window.clearTimeout(id); // will do nothing if no timeout with id is present
}
Я думаю, что самый простой способ добиться этого - хранить все setTimeout
идентификаторы в одном массиве, где вы можете легко выполнять итерацию clearTimeout()
по всем из них.
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]);
}
У меня есть дополнение к ответу Pumbaa80, которое может быть полезно для тех, кто разрабатывает старые IE.
Да, все основные браузеры реализуют идентификаторы тайм-аута как последовательные целые числа (что не требуется по спецификации ). Хотя начальный номер отличается от браузера к браузеру. Кажется, что Opera, Safari, Chrome и IE> 8 запускают идентификаторы тайм-аута с 1, браузеры на основе Gecko с 2 и IE <= 8 с некоторого случайного числа, которое волшебным образом сохраняется при обновлении вкладки. Вы можете узнать это сами .
Все это означает, что в IE <= 8 while (lastTimeoutId--)
цикл может выполняться более 8 раз и показывать сообщение « Сценарий на этой странице вызывает медленную работу Internet Explorer ». Поэтому, если вы не можете сохранить все идентификаторы тайм-аута или не хотите переопределять window.setTimeout, вы можете подумать о сохранении первого идентификатора тайм-аута на странице и очистке тайм-аутов до него.
Выполнить код при ранней загрузке страницы:
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);
};
});
А затем очистите все ожидающие таймауты, которые, вероятно, были установлены иностранным кодом столько раз, сколько захотите.
Как насчет сохранения идентификаторов тайм-аутов в глобальном массиве и определения метода для делегирования вызова функции окну.
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
}
};
Вам нужно переписать window.setTimeout
метод и сохранить его идентификатор тайм-аута.
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();
}
}
Поместите приведенный ниже код перед любым другим скриптом, и он создаст функцию-оболочку для исходного setTimeout
& clearTimeout
.
clearTimeouts
К window
объекту будут добавлены новые методы , которые позволят очистить все (ожидающие) таймауты ( ссылка Gist ).
В других ответах отсутствует полная поддержка возможных аргументов
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);
Для полноты картины я хотел опубликовать общее решение, охватывающее как setTimeout
и setInterval
.
Кажется, браузеры могут использовать один и тот же пул идентификаторов для обоих, но из некоторых ответов на вопрос: Являются ли clearTimeout и clearInterval одинаковыми? , неясно, безопасно ли полагаться clearTimeout
и clearInterval
выполнять одну и ту же функцию или работать только с соответствующими типами таймеров.
Поэтому, когда цель состоит в том, чтобы уничтожить все таймауты и интервалы, вот реализация, которая может быть немного более защитной в разных реализациях, когда не может проверить их все:
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(){}
}
Вы можете использовать его для очистки всех таймеров в текущем окне:
clearAll(window);
Или вы можете использовать его для очистки всех таймеров в iframe
:
clearAll(document.querySelector("iframe").contentWindow);
Я использую Vue с 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
}
}
Уже очень поздно ... но:
По сути, идентификаторы setTimeout / setInterval идут в последовательном порядке, поэтому просто создайте фиктивную функцию тайм-аута, чтобы получить наивысший идентификатор, а затем очистите интервал для всех идентификаторов ниже этого.
const highestId = window.setTimeout(() => {
for (let i = highestId; i >= 0; i--) {
window.clearInterval(i);
}
}, 0);
Используйте глобальный тайм-аут, от которого зависят все ваши другие функции. Это заставит все работать быстрее и упростит управление, хотя добавит некоторую абстракцию в ваш код.
set_timeout
глобальной функции? Не могли бы вы привести пример кода?
Мы только что опубликовали пакет, решающий именно эту проблему.
npm install time-events-manager
При этом вы можете просматривать все таймауты и интервалы с помощью timeoutCollection
& intervalCollection
объектов. Также есть removeAll
функция, которая очищает все таймауты / интервалы как из коллекции, так и из браузера.