javascript: Hapus semua waktu tunggu?

99

Apakah ada cara untuk menghapus semua waktu tunggu dari jendela tertentu? Saya kira batas waktu disimpan di suatu tempat di windowobjek tetapi tidak dapat memastikannya.

Solusi lintas browser apa pun diterima.

marcio
sumber
6
Teman, pertanyaan ini dari 3 tahun yang lalu dan memiliki jawaban yang bagus di dalamnya. Tidak perlu dipusingkan dengan itu.
marcio
Saya mencari ini dan menemukan keduanya. Pertanyaan Anda lebih tua jadi saya pikir akan lebih baik jika Anda mengurangi dua pertanyaan menjadi satu. Punyaku hanya satu suara; beberapa orang lagi perlu memilih untuk menutup, dan tautan duplikat dapat membantu orang lain.
Bernhard Hofmann
2
@Bernard Hofmann Saya tidak yakin apakah ini dianggap sebagai pertanyaan duplikat jika yang ini mendapat jawaban yang lebih baik. Jawaban yang diterima untuk pertanyaan itu dari tahun 2010 adalah "Tidak".
RoboticRenaissance

Jawaban:

148

Mereka tidak ada di objek jendela, tetapi mereka memiliki id, yang (afaik) adalah bilangan bulat berurutan.

Jadi, Anda dapat menghapus semua waktu tunggu seperti ini:

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

while (id--) {
    window.clearTimeout(id); // will do nothing if no timeout with id is present
}
pengguna123444555621
sumber
1
Apakah ini bagian dari spesifikasi, atau mungkinkah bergantung pada implementasi?
Tikhon Jelvis
7
Ini tidak perlu dimulai dari 1. Spesifikasi HTML5 mengatakan "Biarkan pegangan menjadi bilangan bulat yang ditentukan agen pengguna yang lebih besar dari nol yang akan mengidentifikasi waktu tunggu yang akan disetel oleh panggilan ini." yang menyisakan ruang untuk pegangan menjadi bilangan bulat positif termasuk bilangan bulat non-berurutan dan non-kecil.
Mike Samuel
3
Itu sangat pintar, tetapi OP mungkin harus menanyakan apakah ada solusi yang lebih baik yang melacak timer aktif.
Jason Harwig
3
Bukankah ini putaran tak terbatas? Tidak semua browser merender if (0) sebagai false.
Travis J
2
Karena saya bertanya bagaimana cara menghapus SEMUA waktu tunggu, saya menerima jawaban ini. Solusi yang sangat cerdas.
marcio
79

Saya pikir cara termudah untuk mencapai ini adalah dengan menyimpan semua setTimeoutpengenal dalam satu larik, di mana Anda dapat dengan mudah beralih ke clearTimeout()semuanya.

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]);
}
Michael Berkowski
sumber
14
Ini memiliki bonus (atau potensi kerugian, saya kira) hanya membersihkan yang Anda tetapkan, jadi Anda tidak akan secara tidak sengaja membobol kode luar.
Tikhon Jelvis
1
+1, tidak akan menghapus semua waktu tunggu tetapi merupakan solusi yang baik untuk menghapus kelompok waktu tunggu tertentu sekaligus
marcio
1
Ini adalah solusi terbaik karena tidak akan merusak kode eksternal, tetapi karena saya bertanya bagaimana cara menghapus semua waktu tunggu, saya akhirnya menerima jawaban @ Pumbaa80 :)
marcio
2
@marcioAlmada Aneh, tapi keren melihat Anda kembali untuk mengomentari ini lagi 2.5 tahun kemudian :)
Michael Berkowski
6
Mungkin saya ingin menghapus semua waktu tunggu dan interval ketika saya memasuki halaman web yang tidak saya kendalikan, karena mereka memiliki iklan pop-up yang mengganggu yang tidak dimulai sampai setelah adblocker saya berjalan.
RoboticRenaissance
12

Saya memiliki tambahan jawaban Pumbaa80 yang mungkin berguna bagi seseorang yang mengembangkan IE lama.

Ya, semua browser utama menerapkan id waktu tunggu sebagai bilangan bulat berurutan (yang tidak diwajibkan oleh spesifikasi ). Melalui nomor awal berbeda dari browser ke browser. Tampaknya Opera, Safari, Chrome dan IE> 8 memulai id batas waktu dari 1, peramban berbasis Gecko dari 2 dan IE <= 8 dari beberapa nomor acak yang secara ajaib disimpan di seluruh penyegaran tab. Anda bisa menemukannya sendiri .

Semua itu berarti bahwa di IE <= 8 while (lastTimeoutId--)siklus dapat berjalan lebih dari 8 digit kali dan menampilkan pesan " Skrip di halaman ini menyebabkan Internet Explorer berjalan lambat ". Jadi jika Anda tidak dapat menyimpan semua id batas waktu Anda atau tidak ingin menimpa window.setTimeout Anda dapat mempertimbangkan untuk menyimpan id batas waktu pertama pada halaman dan menghapus batas waktu sampai itu.

Jalankan kode pada pemuatan halaman awal:

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

Dan kemudian hapus semua waktu tunggu yang tertunda yang mungkin telah diatur oleh kode asing berkali-kali yang Anda inginkan

Kolya Ay
sumber
ditambah satu untuk memperjelas beberapa info yang lebih detail.
Sanjay
8

Bagaimana dengan menyimpan id batas waktu dalam larik global, dan menentukan metode untuk mendelegasikan panggilan fungsi ke jendela.

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
    }
};
Jaskey
sumber
3

Anda harus menulis ulang window.setTimeoutmetode dan menyimpan ID batas waktunya.

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();
  }
}
tamu
sumber
3

Untuk menghapus semua waktu tunggu, mereka harus "ditangkap" terlebih dahulu :

Letakkan kode di bawah ini sebelum skrip lain dan itu akan membuat fungsi pembungkus untuk setTimeout& clearTimeout.

clearTimeoutsMetode baru akan ditambahkan ke windowObjek, yang memungkinkan penghapusan semua batas waktu (menunggu) ( tautan inti ).

Jawaban lain kekurangan dukungan lengkap untuk kemungkinan argumen yang setTimeout mungkin diterima.

// 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);
vsync
sumber
2

Untuk kelengkapan, saya ingin memposting solusi umum yang mencakup setTimeoutdan setInterval.

Tampaknya browser mungkin menggunakan kumpulan ID yang sama untuk keduanya, tetapi dari beberapa jawaban untuk Apakah clearTimeout dan clearInterval sama? , tidak jelas apakah aman mengandalkan clearTimeoutdan clearIntervalmenjalankan fungsi yang sama atau hanya bekerja pada jenis pengatur waktu masing-masing.

Oleh karena itu, jika tujuannya adalah untuk menghentikan semua waktu tunggu dan interval, berikut adalah penerapan yang mungkin sedikit lebih defensif di seluruh penerapan saat tidak dapat menguji semuanya:

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

Anda dapat menggunakannya untuk menghapus semua timer di jendela saat ini:

clearAll(window);

Atau Anda dapat menggunakannya untuk menghapus semua pengatur waktu di iframe:

clearAll(document.querySelector("iframe").contentWindow);
Chris Calo
sumber
Perlu diingat bahwa pendekatan ini menghancurkan pengamat vue-cli-service sehingga Anda tidak dapat melakukan hot-reload saat membersihkan semua timeout dan interval waktu. Saya berasumsi itu sama untuk pengamat reload panas lainnya untuk kerangka kerja seperti (angular, react, ember dll)
Michail Michailidis
1

Saya menggunakan Vue dengan Typecript.

    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
        }
    }
LuanLuanLuan
sumber
0

Gunakan waktu tunggu global tempat semua fungsi Anda lainnya mendapatkan pengaturan waktu. Ini akan membuat semuanya berjalan lebih cepat, dan lebih mudah dikelola, meskipun itu akan menambahkan beberapa abstraksi ke kode Anda.

Travis J
sumber
Saya tidak sepenuhnya memahami Anda. Anda bermaksud memperluas perilaku set_timeoutfungsi global? Bisakah Anda memberikan contoh kode?
marcio
1
Maksud saya, Anda memiliki satu waktu tunggu global yang berjalan setiap 50 md. Setiap fungsi lain yang memerlukan elemen waktu akan mengambilnya dari waktu tunggu global. Google beralih ke ini untuk efisiensi, meskipun saya tidak dapat lagi menemukan artikel yang mengutipnya.
Travis J
0

Kami baru saja menerbitkan paket yang memecahkan masalah ini.

npm install time-events-manager

Dengan itu, Anda dapat melihat semua waktu tunggu dan interval melalui timeoutCollection& intervalCollectionobjek. Ada juga removeAllfungsi yang menghapus semua waktu tunggu / interval baik dari koleksi dan browser.

Bar Goldinfeld
sumber
0

Ini sudah sangat terlambat ... tapi:

Pada dasarnya, setTimeout / setInterval ID berjalan berurutan, jadi buat saja fungsi waktu tunggu dummy untuk mendapatkan ID tertinggi, lalu hapus interval pada semua ID yang lebih rendah dari itu.

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