javascript: очистити всі тайм-аути?


99

Чи є спосіб очистити весь час виходу з даного вікна? Я припускаю, що тайм-аути зберігаються десь в windowоб'єкті, але не могли підтвердити це.

Будь-яке крос-браузерне рішення вітається.



6
Чувак, це питання з 3 років тому і на нього чудові відповіді. Не потрібно з цим возитися.
marcio

Я шукав це і знайшов обоє. Ваш був старший, тому я подумав, що було б добре вести господарство, щоб звести два питання до одного. Моє - це лише один голос; Для закриття потрібно буде проголосувати ще декілька людей, і дублікат посилання може допомогти іншим.
Бернхард Хофманн

2
@ Бернар Хофманн Я не впевнений, чи вважається це повторюваним запитанням, чи отримав кращу відповідь. Відповідь на цю відповідь з 2010 року була "Ні".
RoboticRenaissance

Відповіді:


148

Їх немає у об’єкті вікна, але вони мають ідентифікатори, які (afaik) є послідовними цілими числами.

Таким чином, ви можете очистити всі тайм-аути так:

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

while (id--) {
    window.clearTimeout(id); // will do nothing if no timeout with id is present
}

1
Це частина специфікації, чи вона може залежати від реалізації?
Тіхон Єлвіс

7
Його не потрібно починати з 1. Специфікація HTML5 говорить: "Нехай ручка буде цілим числом, визначеним користувачем-агентом, яке перевищує нуль, ідентифікувати час очікування, встановлений цим викликом." що залишає місце для ручки будь-якого натурального цілого числа, включаючи непослідовні та не малі цілі числа.
Майк Самуель

3
Це дуже розумно, але ОП, мабуть, повинен запитати, чи є краще рішення, яке слідкує за активними таймерами.
Джейсон Харвіг

3
Це не безкінечна петля? Не всі браузери відображають, якщо (0) неправдивими.
Травіс J

2
Оскільки я запитав, як очистити ВСІ тайм-аути, я приймаю цю відповідь. Дуже розумне рішення.
marcio

79

Я думаю, що найпростішим способом досягти цього було б зберігання всіх 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]);
}

14
У цьому є бонус (або можливий недолік, я думаю) очищення лише тих, які ви встановили, так що ви навмисно не зламаєте зовнішній код.
Тихон Єлвіс

1
+1, не очистить всі тайм-аути, але це вдале рішення для очищення конкретної групи тайм-аутів відразу
marcio

1
Це найкраще рішення, оскільки воно не порушить зовнішній код, але оскільки я запитав, як очистити всі проміжки часу, я в кінцевому підсумку прийняв відповідь @ Pumbaa80 :)
marcio

2
@marcioAlmada Дивно, але приємно бачити, що ви повертаєтесь до коментарів знову 2,5 року пізніше :)
Michael Berkowski

6
Можливо, я хотів би очистити всі тайм-аути та інтервали під час входу на веб-сторінку, яку я не контролюю, оскільки у них є дратівлива спливаюча реклама, яка починається до моменту запуску мого адблокера.
RoboticRenaissance

12

У мене є доповнення до відповіді 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);
    };
});

А потім зніміть всі очікувані очікування, які, ймовірно, були встановлені іноземним кодом стільки разів, скільки вам потрібно


плюс один для уточнення більш детальної інформації.
Санджай

8

Як щодо зберігання ідентифікаторів тайм-ауту в глобальному масиві та визначення способу делегування виклику функції вікні.

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

3

Ви повинні переписати 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();
  }
}

3

Щоб очистити всі тайм-аути, їх потрібно спочатку "захопити" :

Розмістіть наведений нижче код перед будь-яким іншим сценарієм, і він створить функцію обгортки для оригіналу 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);

2

Для повноти я хотів опублікувати загальне рішення, яке охоплює і те, 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-cli, тому ви не можете робити повторне завантаження під час чищення всіх тайм-аутів та інтервалів часу. Я припускаю, що це те саме для інших спостерігачів гарячого перезавантаження для таких кадрів, як (кутовий, реагувати, ембер тощо)
Michail Michailidis

1

Я використовую 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
        }
    }

0

Використовуйте глобальний тайм-аут, з якого виходять усі ваші інші функції. Це зробить все швидше і легше керувати, хоча це додасть деякої абстракції у ваш код.


Я вас не цілком розумію. Ви маєте на увазі розширити поведінку set_timeoutглобальної функції? Чи можете ви навести приклад коду?
marcio

1
Я просто мав на увазі, що у вас є один глобальний тайм-аут, що працює один раз кожні 50 мс. Будь-яка інша функція, яка вимагала б елемента синхронізації, потім захопила б її з глобального тайм-ауту. Google перейшов до цього для підвищення ефективності, хоча я не можу знайти статті, в якій його цитують.
Travis J

0

Ми щойно опублікували пакет, що вирішує цю проблему.

npm install time-events-manager

З цим ви можете переглядати всі тайм-аути та інтервали через timeoutCollection& intervalCollectionоб’єкти. Існує також removeAllфункція, яка очищає всі тайм-аути / інтервали як з колекції, так і з браузера.


0

Це дуже пізно ... але:

В основному, ідентифікатор setTimeout / setInterval йде в послідовному порядку, тому просто створіть фіктивну функцію тайм-ауту, щоб отримати найвищий ідентифікатор, а потім очистіть інтервал для всіх ідентифікаторів, нижчих за цей.

const highestId = window.setTimeout(() => {
  for (let i = highestId; i >= 0; i--) {
    window.clearInterval(i);
  }
}, 0);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.