javascript: ล้างการหมดเวลาทั้งหมดหรือไม่


104

มีวิธีล้างเวลาทั้งหมดออกจากหน้าต่างที่กำหนดหรือไม่? ฉันคิดว่าการหมดเวลาถูกเก็บไว้ที่ใดที่หนึ่งในwindowวัตถุ แต่ไม่สามารถยืนยันได้

ยินดีต้อนรับโซลูชันข้ามเบราว์เซอร์ใด ๆ



6
เพื่อนคำถามนี้มาจาก 3 ปีที่แล้วและมีคำตอบที่ดี ไม่ต้องไปยุ่งเรื่องนั้น
marcio

ฉันค้นหาสิ่งนี้และพบทั้งสองอย่าง คุณอายุมากขึ้นดังนั้นฉันจึงคิดว่าควรดูแลทำความสะอาดที่ดีเพื่อลดสองคำถามให้เหลือเพียงข้อเดียว ฉันเป็นเพียงหนึ่งโหวต มีคนอีกไม่กี่คนที่จะต้องลงคะแนนเพื่อปิดและลิงก์ที่ซ้ำกันอาจช่วยผู้อื่นได้
Bernhard Hofmann

2
@Bernard Hofmann ฉันไม่แน่ใจว่ามันนับเป็นคำถามที่ซ้ำกันหรือไม่ถ้าคำถามนี้มีคำตอบที่ดีกว่า คำตอบที่ได้รับการยอมรับจากปี 2010 คือ "ไม่"
RoboticRenaissance

คำตอบ:


151

พวกเขาไม่ได้อยู่ในวัตถุหน้าต่าง แต่มีรหัสซึ่ง (afaik) เป็นจำนวนเต็มติดต่อกัน

ดังนั้นคุณสามารถล้างการหมดเวลาทั้งหมดได้ดังนี้:

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

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

1
เป็นส่วนหนึ่งของข้อกำหนดนี้หรืออาจขึ้นอยู่กับการนำไปใช้งาน
Tikhon Jelvis

7
ไม่จำเป็นต้องเริ่มต้นที่ 1 ข้อมูลจำเพาะHTML5ระบุว่า "ให้หมายเลขอ้างอิงเป็นจำนวนเต็มที่ผู้ใช้กำหนดโดยตัวแทนซึ่งมีค่ามากกว่าศูนย์ซึ่งจะระบุระยะหมดเวลาที่จะกำหนดโดยการเรียกนี้ ซึ่งทำให้จุดจับเป็นจำนวนเต็มบวกใด ๆ รวมทั้งจำนวนเต็มไม่ต่อเนื่องและจำนวนเต็มไม่เล็ก
Mike Samuel

3
นั่นเป็นเรื่องที่ฉลาดมาก แต่ OP ควรถามว่ามีวิธีแก้ไขที่ดีกว่าในการติดตามตัวจับเวลาที่ใช้งานอยู่หรือไม่
Jason Harwig

3
นี่ไม่ใช่การวนซ้ำที่ไม่มีที่สิ้นสุดหรือ? เบราว์เซอร์บางตัวไม่แสดงผลถ้า (0) เป็นเท็จ
Travis J

2
เนื่องจากฉันถามวิธีล้างการหมดเวลาทั้งหมดฉันจึงยอมรับคำตอบนี้ วิธีแก้ปัญหาที่ชาญฉลาดมาก
marcio

80

ฉันคิดว่าวิธีที่ง่ายที่สุดในการทำให้สำเร็จคือการจัดเก็บตัว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
สิ่งนี้มีโบนัส (หรือข้อเสียเปรียบที่อาจเกิดขึ้นฉันเดา) จากการล้างเฉพาะรายการที่คุณตั้งไว้ดังนั้นคุณจะไม่ทำลายรหัสภายนอกโดยไม่ได้ตั้งใจ
Tikhon Jelvis

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--)วงจรอาจทำงานเกิน 8digits ครั้งและแสดงข้อความ " A script ในหน้านี้ทำให้ 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);
    };
});

จากนั้นล้างการหมดเวลาที่รอดำเนินการทั้งหมดที่อาจถูกกำหนดโดยรหัสต่างประเทศหลายครั้งที่คุณต้องการ


บวกหนึ่งเพื่อชี้แจงข้อมูลรายละเอียดเพิ่มเติม
Sanjay

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

4

คุณต้องเขียน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

หากต้องการล้างการหมดเวลาทั้งหมดจะต้อง "จับภาพ" ก่อน :

วางด้านล่างรหัสก่อนสคริปต์อื่น ๆและมันจะสร้างฟังก์ชั่นเสื้อคลุมสำหรับต้นฉบับและsetTimeoutclearTimeout

clearTimeoutsวิธีการใหม่จะถูกเพิ่มเข้าไปในwindowObject ซึ่งจะช่วยให้สามารถล้างการหมดเวลาทั้งหมด (รอดำเนินการ) ได้ ( ลิงก์ 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.

ดูเหมือนว่าเบราว์เซอร์อาจใช้กลุ่ม ID เดียวกันสำหรับทั้งสอง แต่จากคำตอบบางส่วนของAre 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 ดังนั้นคุณจึงไม่สามารถทำการ hot-reload ได้เมื่อทำความสะอาดการหมดเวลาและช่วงเวลาทั้งหมด ฉันคิดว่ามันเหมือนกันสำหรับนักดูการรีโหลดแบบร้อนอื่น ๆ สำหรับเฟรมเวิร์กเช่น (เชิงมุม, ปฏิกิริยา, ถ่าน ฯลฯ )
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
        }
    }

1

นี่มันดึกมากแล้ว ... แต่:

โดยทั่วไป setTimeout / setInterval ID จะเรียงตามลำดับกันดังนั้นเพียงแค่สร้างฟังก์ชันการหมดเวลาจำลองเพื่อให้ได้ ID สูงสุดจากนั้นล้างช่วงเวลาของ ID ทั้งหมดที่ต่ำกว่านั้น

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

นี่คือทางออกที่ดีที่สุดสำหรับฉัน !! ขอบคุณ charri
Locos

0

ใช้การหมดเวลาส่วนกลางซึ่งฟังก์ชันอื่น ๆ ทั้งหมดของคุณได้มาจากเวลา สิ่งนี้จะทำให้ทุกอย่างทำงานได้เร็วขึ้นและจัดการได้ง่ายขึ้นแม้ว่าจะเพิ่มนามธรรมให้กับโค้ดของคุณก็ตาม


ฉันไม่เข้าใจคุณทั้งหมด คุณหมายถึงการขยายพฤติกรรมของset_timeoutฟังก์ชันส่วนกลางหรือไม่? คุณสามารถให้รหัสตัวอย่างได้หรือไม่?
marcio

1
ฉันหมายความว่าคุณมีการหมดเวลาทั่วโลกหนึ่งครั้งทุกๆ 50 มิลลิวินาที ฟังก์ชั่นอื่น ๆ ทั้งหมดที่ต้องการองค์ประกอบเวลาก็จะคว้ามันจากการหมดเวลาทั่วโลก Google เปลี่ยนมาใช้สิ่งนี้เพื่อประสิทธิภาพแม้ว่าฉันจะไม่พบบทความที่อ้างถึงอีกต่อไป
Travis J

0

เราเพิ่งเผยแพร่แพ็คเกจเพื่อแก้ปัญหานี้

npm install time-events-manager

ด้วยวิธีนี้คุณสามารถดูการหมดเวลาและช่วงเวลาทั้งหมดผ่านtimeoutCollection& intervalCollectionวัตถุ นอกจากนี้ยังมีremoveAllฟังก์ชั่นที่ล้างการหมดเวลา / ช่วงเวลาทั้งหมดทั้งจากคอลเลคชันและเบราว์เซอร์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.