javascript: Tüm zaman aşımları silinsin mi?


101

Belirli bir pencereden tüm zaman aşımlarını temizlemenin bir yolu var mı? Sanırım zaman aşımları windownesnede bir yerde saklanıyor, ancak bunu teyit edemedim.

Herhangi bir çapraz tarayıcı çözümü kabul edilir.



6
Dostum, bu soru 3 yıl öncesine ait ve harika cevapları var. Bununla uğraşmaya gerek yok.
marcio

Bunu aradım ve ikisini de buldum. Seninki daha yaşlıydı, bu yüzden iki soruyu bire indirmenin iyi bir temizlik olacağını düşündüm. Benimki sadece bir oy; Kapatmak için birkaç kişinin daha oy vermesi gerekecek ve yinelenen bağlantı başkalarına yardımcı olabilir.
Bernhard Hofmann

2
@Bernard Hofmann Bunun daha iyi bir cevabı varsa yinelenen bir soru olarak sayılıp sayılmayacağından emin değilim. 2010'dan itibaren kabul edilen cevap "Hayır" oldu.
RoboticRenaissance

Yanıtlar:


149

Pencere nesnesinde değillerdir, ancak (afaik) ardışık tam sayı olan kimlikleri vardır.

Böylece tüm zaman aşımlarını şu şekilde temizleyebilirsiniz:

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

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

1
Bu şartnamenin bir parçası mı yoksa uygulamaya bağlı olabilir mi?
Tikhon Jelvis

7
1'den başlamasına gerek yoktur. HTML5 belirtimi, "İşleci, bu çağrı tarafından ayarlanacak zaman aşımını belirleyecek, sıfırdan büyük bir kullanıcı aracısı tanımlı tamsayı olsun" der. tutacağın ardışık olmayan ve küçük olmayan tamsayılar da dahil olmak üzere herhangi bir pozitif tam sayı olması için yer bırakır.
Mike Samuel

3
Bu çok zekice, ancak OP muhtemelen aktif zamanlayıcıların kaydını tutan daha iyi bir çözüm olup olmadığını sormalıdır.
Jason Harwig

3
Bu sonsuz bir döngü değil mi? Tüm tarayıcılar eğer (0) 'ı yanlış olarak oluşturmaz.
Travis J

2
TÜM zaman aşımlarını nasıl temizleyeceğimi sorduğum için bu yanıtı kabul ediyorum. Çok akıllıca bir çözüm.
marcio

79

Bence bunu başarmanın en kolay yolu, tüm setTimeouttanımlayıcıları kolayca yineleyebileceğiniz tek bir dizide saklamaktır 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
Bu bonusu (ya da potansiyel dezavantajı, sanırım) sadece olanları temizleme vardır sen istemeden dış kodu kırmak olmaz, böylece ayarlayın.
Tikhon Jelvis

1
+1, tüm zaman aşımlarını temizlemeyecek, ancak belirli bir zaman aşımı grubunu bir kerede temizlemek için iyi bir çözüm
marcio

1
Bu dış kodu kırmak olmaz çünkü en iyi çözümdür, ama tüm zaman aşımları nasıl temizleneceğini istedi beri :) Pumbaa80 cevap @ gibi kabullendi
marcio

2
@marcioAlmada Garip, ancak 2.5 yıl sonra bu konu hakkında tekrar yorum yapmak için geri döndüğünüzü görmek çok güzel :)
Michael Berkowski

6
Belki de kontrol etmediğim bir web sayfasına girdiğimde tüm zaman aşımlarını ve aralıkları temizlemek istiyorum, çünkü reklam engelleyicim çalışana kadar başlamayan can sıkıcı bir açılır reklamı var.
RoboticRenaissance

12

Ben bir ekleme sahip Pumbaa80 cevabı eski IE'lerin için gelişmekte birisi için yararlı olabilir.

Evet, tüm büyük tarayıcılar zaman aşımı kimliklerini ardışık tamsayılar olarak uygular ( spesifikasyon tarafından gerekli değildir ). Başlangıç ​​numarası tarayıcıdan tarayıcıya farklılık gösterse de. Görünüşe göre Opera, Safari, Chrome ve IE> 8, sekme yenilemede sihirli bir şekilde kaydedilen bazı rastgele sayılardan 1'den Gecko tabanlı tarayıcılar ve IE <= 8'den zaman aşımı kimliklerini başlatıyor. Sen edebilirsiniz kendin keşfetmek .

Tüm bunlar, IE <= 8'de while (lastTimeoutId--)döngünün 8 basamaktan fazla çalışabileceği ve " Bu sayfadaki bir komut dosyası Internet Explorer'ın yavaş çalışmasına neden oluyor " mesajını gösterebileceği anlamına gelir . Bu nedenle, tüm zaman aşımı kimliklerini kaydedemezseniz veya window.setTimeout'u geçersiz kılmak istemiyorsanız , bir sayfadaki ilk zaman aşımı kimliğini kaydetmeyi ve bu zaman aşımını temizlemeyi düşünebilirsiniz.

Kodu erken sayfa yüklemesinde yürütün:

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

Ve sonra, muhtemelen yabancı kod tarafından birçok kez ayarlanmış olan tüm bekleyen zaman aşımlarını temizleyin


artı biraz daha ayrıntılı bilgileri açıklığa kavuşturmak için bir tane.
Sanjay

8

Zaman aşımı kimliklerini global bir dizide depolamaya ve işlev çağrısını pencereye devretmek için bir yöntem tanımlamaya ne dersiniz?

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.setTimeoutYöntemi yeniden yazmanız ve zaman aşımı kimliğini kaydetmeniz gerekir.

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

Tüm temizlemek için zaman aşımı onlar "yakalanan" olmalıdır ilk :

Aşağıdaki kodu başka herhangi bir komut dosyasının önüne yerleştirin ve orijinal setTimeout& için bir sarmalayıcı işlevi oluşturacaktır clearTimeout.

Nesneye, tüm (bekleyen) zaman aşımlarının ( Gist bağlantısı ) temizlenmesine izin verecek yeni bir clearTimeoutsyöntem eklenecektir .window

Diğer cevaplar , alınabilecek olası argümanlar için tam desteğe sahip değildir . 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

Bütünlüğü sağlamak için, bunu kapakları hem genel bir çözüm sonrası istedim setTimeoutve setInterval.

Görünüşe göre tarayıcılar her ikisi için aynı kimlik havuzunu kullanıyor olabilir, ancak bazı yanıtlardan Are clearTimeout ve clearInterval aynı mı? , aynı işleve güvenmenin clearTimeoutve bunu clearIntervalgerçekleştirmenin mi yoksa yalnızca ilgili zamanlayıcı türlerinde çalışmanın güvenli olup olmadığı açık değildir .

Bu nedenle, amaç tüm zaman aşımlarını ve aralıkları sonlandırmak olduğunda, işte hepsini test edemediğinde uygulamalar arasında biraz daha savunmacı olabilecek bir uygulama:

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

Mevcut penceredeki tüm zamanlayıcıları temizlemek için kullanabilirsiniz:

clearAll(window);

Ya da aşağıdaki tüm zamanlayıcıları temizlemek için kullanabilirsiniz iframe:

clearAll(document.querySelector("iframe").contentWindow);

Bu yaklaşımın vue-cli-service watcher'ı yok ettiğini ve böylece tüm zaman aşımlarını ve zaman aralıklarını temizlerken sıcak yeniden yükleme yapamayacağınızı unutmayın. (Köşeli, tepki, köz vb.)
Michail Michailidis,

1

Typecript ile Vue kullanıyorum.

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

1

Bu çok geç ... ama:

Temel olarak, setTimeout / setInterval ID'leri ardışık sırada gider, bu yüzden en yüksek ID'yi elde etmek için sadece bir kukla zaman aşımı işlevi oluşturun, ardından bundan daha düşük tüm ID'lerde aralığı temizleyin.

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

Bu benim için en iyi çözümdü !! teşekkürler charri
Locos

0

Diğer tüm işlevlerinizin zamanlamayı elde ettiği global bir zaman aşımı kullanın. Bu, kodunuza biraz soyutlama katacak olsa da, her şeyin daha hızlı çalışmasını sağlayacak ve yönetilmesi daha kolay olacaktır.


Seni tam olarak anlamıyorum set_timeoutGlobal işlevin davranışını genişletmek mi istiyorsunuz? Örnek bir kod verebilir misiniz?
marcio

1
Sadece her 50 ms'de bir çalışan global bir zaman aşımınız olduğunu kastetmiştim. Bir zamanlama öğesi gerektiren diğer tüm işlevler, onu küresel zaman aşımından alır. Google, verimlilik için buna geçti, ancak alıntı yapan makaleyi artık bulamıyorum.
Travis J

0

Tam olarak bu sorunu çözen bir paket yayınladık.

npm install time-events-manager

Bununla, tüm zaman aşımlarını ve aralıkları timeoutCollection& intervalCollectionnesneler aracılığıyla görüntüleyebilirsiniz . Ayrıca removeAllhem koleksiyondaki hem de tarayıcıdaki tüm zaman aşımlarını / aralıkları temizleyen bir işlev vardır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.