มีคนอธิบายฟังก์ชั่น“ debounce” ใน Javascript ได้ไหม


151

ฉันสนใจฟังก์ชั่น "debouncing" ใน javascript เขียนที่นี่: http://davidwalsh.name/javascript-debounce-function

น่าเสียดายที่รหัสไม่ได้อธิบายอย่างชัดเจนเพียงพอสำหรับฉันที่จะเข้าใจ ทุกคนสามารถช่วยฉันคิดออกว่ามันทำงานอย่างไร (ฉันทิ้งความคิดเห็นไว้ด้านล่าง) ในระยะสั้นฉันแค่ไม่เข้าใจว่ามันทำงานอย่างไร

   // Returns a function, that, as long as it continues to be invoked, will not
   // be triggered. The function will be called after it stops being called for
   // N milliseconds.


function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};

แก้ไข: ข้อมูลโค้ดที่คัดลอกมาก่อนหน้านี้มีcallNowจุดผิด


1
หากคุณโทรหาclearTimeoutบางอย่างที่ไม่ใช่รหัสตัวจับเวลาที่ถูกต้องมันจะไม่ทำอะไรเลย
Ry-

@ ปลอม, พฤติกรรมมาตรฐานที่ถูกต้องคืออะไร?
Pacerier

3
@Pacerier ใช่มันอยู่ในข้อมูลจำเพาะ : "ถ้าหมายเลขอ้างอิงไม่ได้ระบุรายการในรายการตัวจับเวลาที่ใช้งานของWindowTimersวัตถุซึ่งเป็นวิธีการที่เรียกใช้วิธีการไม่ทำอะไรเลย"
Mattias Buelens

คำตอบ:


134

รหัสในคำถามถูกเปลี่ยนแปลงเล็กน้อยจากรหัสในลิงค์ ในลิงค์มีการตรวจสอบ(immediate && !timeout)ก่อนสร้างการหมดเวลาใหม่ การมีมันหลังจากทำให้โหมดทันทีเพื่อไม่ให้เกิดไฟไหม้ ฉันได้อัปเดตคำตอบของฉันเพื่อใส่หมายเหตุรุ่นที่ใช้งานได้จากลิงก์

function debounce(func, wait, immediate) {
  // 'private' variable for instance
  // The returned function will be able to reference this due to closure.
  // Each call to the returned function will share this common timer.
  var timeout;

  // Calling debounce returns a new anonymous function
  return function() {
    // reference the context and args for the setTimeout function
    var context = this,
      args = arguments;

    // Should the function be called now? If immediate is true
    //   and not already in a timeout then the answer is: Yes
    var callNow = immediate && !timeout;

    // This is the basic debounce behaviour where you can call this 
    //   function several times, but it will only execute once 
    //   [before or after imposing a delay]. 
    //   Each time the returned function is called, the timer starts over.
    clearTimeout(timeout);

    // Set the new timeout
    timeout = setTimeout(function() {

      // Inside the timeout function, clear the timeout variable
      // which will let the next execution run when in 'immediate' mode
      timeout = null;

      // Check if the function already ran with the immediate flag
      if (!immediate) {
        // Call the original function with apply
        // apply lets you define the 'this' object as well as the arguments 
        //    (both captured before setTimeout)
        func.apply(context, args);
      }
    }, wait);

    // Immediate mode and no wait timer? Execute the function..
    if (callNow) func.apply(context, args);
  }
}

/////////////////////////////////
// DEMO:

function onMouseMove(e){
  console.clear();
  console.log(e.x, e.y);
}

// Define the debounced function
var debouncedMouseMove = debounce(onMouseMove, 50);

// Call the debounced function on every mouse move
window.addEventListener('mousemove', debouncedMouseMove);


1
สำหรับการimmediate && timeoutตรวจสอบ จะไม่มีเสมอtimeout(เพราะtimeoutถูกเรียกก่อนหน้านี้) นอกจากนี้สิ่งที่ดีclearTimeout(timeout)ทำเมื่อมีการประกาศ (ทำให้ไม่ได้กำหนด) และล้างก่อนหน้านี้
Startec

การimmediate && !timeoutตรวจสอบนี้ใช้สำหรับการกำหนด debounce ด้วยimmediateแฟล็ก สิ่งนี้จะเรียกใช้ฟังก์ชั่นทันที แต่กำหนดการwaitหมดเวลาก่อนหากสามารถดำเนินการได้อีกครั้ง ดังนั้น!timeoutส่วนนั้นก็บอกว่า 'ขอโทษนะนี่ถูกดำเนินการแล้วภายในหน้าต่างที่กำหนดไว้' ... จำได้ว่าฟังก์ชั่น setTimeout จะล้างมันทำให้การเรียกครั้งต่อไปดำเนินการได้
Malk

1
เหตุใดการหมดเวลาจึงต้องตั้งค่าเป็นศูนย์ภายในsetTimeoutฟังก์ชัน นอกจากนี้ฉันได้ลองใช้รหัสนี้แล้วสำหรับฉันการส่งผ่านไปยังtrueทันทีเป็นการป้องกันไม่ให้ฟังก์ชันถูกเรียกเลย (แทนที่จะถูกเรียกหลังจากล่าช้า) สิ่งนี้เกิดขึ้นกับคุณหรือไม่
Startec

ฉันมีคำถามที่คล้ายกันเกี่ยวกับทันทีหรือไม่ ทำไมมันต้องมีพารามิเตอร์ทันที การตั้งค่าการรอเป็น 0 ควรมีผลเหมือนกันใช่ไหม และตามที่ @Startec พูดถึงพฤติกรรมนี้ค่อนข้างแปลก
zeroliu

2
หากคุณเพียงแค่เรียกใช้ฟังก์ชันคุณจะไม่สามารถกำหนดตัวจับเวลารอก่อนที่จะสามารถเรียกใช้ฟังก์ชันนั้นได้อีกครั้ง คิดว่าเป็นเกมที่ผู้ใช้ mash คีย์ไฟ คุณต้องการให้ระบบเรียกใช้งานทันที แต่จะไม่ทำงานอีกต่อไปอีกหนึ่งมิลลิวินาทีไม่ว่าผู้ใช้จะกดปุ่มเร็วแค่ไหน
Malk

57

สิ่งสำคัญที่ควรทราบคือการdebounceสร้างฟังก์ชั่นที่ "ปิด" timeoutตัวแปร timeoutการเข้าพักตัวแปรที่สามารถเข้าถึงได้ในระหว่างการเรียกร้องของฟังก์ชั่นการผลิตทุกแม้หลังจากที่debounceตัวเองได้กลับมาและสามารถเปลี่ยนแปลงได้ตลอดสายที่แตกต่างกัน

แนวคิดทั่วไปสำหรับdebounceต่อไปนี้:

  1. เริ่มต้นโดยไม่มีการหมดเวลา
  2. หากเรียกใช้ฟังก์ชันที่ผลิตให้ล้างและรีเซ็ตการหมดเวลา
  3. หากการหมดเวลาใช้งานถูกเรียกใช้ฟังก์ชันดั้งเดิม

จุดแรกเป็นเพียงเป็นจริงเพียงvar timeout; undefinedโชคดีที่clearTimeoutค่อนข้างหละหลวมเกี่ยวกับอินพุต: การผ่านundefinedตัวระบุตัวจับเวลาทำให้มันไม่ทำอะไรเลย

จุดที่สองจะทำโดยฟังก์ชั่นที่ผลิต ก่อนอื่นจะเก็บข้อมูลบางอย่างเกี่ยวกับการโทร ( thisบริบทและarguments) ในตัวแปรเพื่อให้สามารถใช้สิ่งเหล่านี้ในภายหลังสำหรับการโทรที่ถูกปฏิเสธ จากนั้นก็ล้างหมดเวลา (ถ้ามีหนึ่งชุด) setTimeoutแล้วสร้างใหม่เพื่อใช้แทนได้โดยใช้ โปรดทราบว่าสิ่งนี้จะเขียนทับค่าของtimeoutและค่านี้ยังคงมีอยู่มากกว่าการเรียกใช้ฟังก์ชันหลายรายการ! วิธีนี้ช่วยให้ debounce ทำงานได้จริง: หากฟังก์ชั่นนั้นถูกเรียกว่าหลาย ๆ ครั้งtimeoutจะถูกเขียนทับด้วยตัวจับเวลาใหม่หลายครั้ง หากไม่ใช่กรณีนี้การโทรหลายครั้งจะทำให้ตัวนับหลายตัวเริ่มทำงานซึ่งการโทรทั้งหมดยังคงใช้งานอยู่การโทรจะล่าช้า แต่ไม่หักล้าง

จุดที่สามจะทำในการโทรกลับหมดเวลา มันยกเลิกtimeoutตัวแปรและทำการเรียกใช้งานจริงโดยใช้ข้อมูลการโทรที่เก็บไว้

immediateธงควรจะควบคุมไม่ว่าจะเป็นฟังก์ชั่นควรจะเรียกว่าก่อนหรือหลังการจับเวลา ถ้ามันเป็นfalseฟังก์ชั่นเดิมไม่ได้เรียกว่าจนกระทั่งหลังจากการจับเวลาจะตี หากเป็นtrueเช่นนั้นฟังก์ชั่นดั้งเดิมจะถูกเรียกใช้ก่อนและจะไม่ถูกเรียกอีกต่อไปจนกว่าจะถึงตัวจับเวลา

อย่างไรก็ตามฉันเชื่อว่าการif (immediate && !timeout)ตรวจสอบไม่ถูกต้อง: timeoutเพิ่งถูกตั้งค่าเป็นตัวระบุตัวจับเวลาที่ส่งคืนโดยsetTimeoutดังนั้น!timeoutจะอยู่falseที่จุดนั้นเสมอดังนั้นจึงไม่สามารถเรียกใช้ฟังก์ชันได้ รุ่นปัจจุบันของ underscore.jsดูเหมือนว่าจะมีการตรวจสอบความแตกต่างกันเล็กน้อยที่จะประเมินimmediate && !timeout ก่อนที่จะsetTimeoutโทร (อัลกอริทึมก็แตกต่างกันเล็กน้อยเช่นไม่ได้ใช้clearTimeout) นั่นเป็นเหตุผลที่คุณควรลองใช้ไลบรารี่รุ่นล่าสุดของคุณ :-)


"โปรดทราบว่าสิ่งนี้จะเขียนทับค่าการหมดเวลาและค่านี้จะคงอยู่ในการเรียกใช้ฟังก์ชันหลายครั้ง" ไม่ใช่การหมดเวลาในเครื่องสำหรับการโทรดีบั๊กแต่ละครั้งหรือไม่ มันถูกประกาศด้วย var แต่ละครั้งจะถูกเขียนทับอย่างไร นอกจากนี้ทำไมต้องตรวจสอบ!timeoutในตอนท้าย? ทำไมมันไม่อยู่เสมอ (เพราะถูกตั้งค่าเป็นsetTimeout(function() etc.)
Startec

2
@Startec มันเป็นแบบท้องถิ่นสำหรับการโทรแต่ละครั้งdebounceใช่ แต่จะถูกแชร์ระหว่างการโทรไปยังฟังก์ชันที่ส่งคืน (ซึ่งเป็นฟังก์ชันที่คุณจะใช้) ยกตัวอย่างเช่นในg = debounce(f, 100)ค่าของยังคงมีอยู่ในช่วงหลายสายไปtimeout gการ!timeoutตรวจสอบในตอนท้ายเป็นความผิดพลาดที่ฉันเชื่อและไม่ได้อยู่ในรหัส underscore.js ปัจจุบัน
Mattias Buelens

เหตุใดจึงต้องยกเลิกการหมดเวลาก่อนในฟังก์ชันส่งคืน (ทันทีหลังจากประกาศ) นอกจากนี้จะถูกตั้งค่าเป็น null ภายในฟังก์ชั่น setTimeout ไม่ซ้ำซ้อนนี้หรือไม่ (ครั้งแรกมันจะถูกล้างออกแล้วก็มีการตั้งค่าnullในการทดสอบของฉันกับโค้ดข้างต้น, การตั้งค่าได้ทันทีเพื่อทำให้ความจริงฟังก์ชั่นไม่เรียกที่ทุกคนตามที่คุณกล่าวถึงวิธีการแก้ปัญหาใด ๆ โดยไม่ต้องขีดเส้นใต้..
Startec

34

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

ฟังก์ชั่น Throttled ดำเนินการแล้วรอระยะเวลาที่กำหนดได้ก่อนที่จะมีสิทธิ์ยิงได้อีกครั้ง

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

Throttle นั้นยอดเยี่ยมสำหรับจุดสิ้นสุดเรียลไทม์ที่คุณต้องการอนุญาตให้ผู้ใช้เรียกใช้หนึ่งครั้งต่อช่วงเวลาที่กำหนด

ตรวจสอบUnderscore.jsสำหรับการใช้งานของพวกเขาด้วย


25

ฉันเขียนโพสต์ชื่อDemistifying Debounce ใน JavaScriptซึ่งฉันอธิบายได้อย่างชัดเจนว่าฟังก์ชั่น debounce นั้นทำงานอย่างไรและรวมตัวอย่างไว้ด้วย

ฉันก็ไม่เข้าใจเช่นกันว่าฟังก์ชั่น debounce นั้นทำงานอย่างไรเมื่อฉันเจอมันครั้งแรก แม้ว่าจะมีขนาดค่อนข้างเล็ก แต่จริงๆแล้วพวกเขาใช้แนวคิด JavaScript ขั้นสูงที่น่ารัก! การยึดเกาะกับขอบเขตการปิดและsetTimeoutวิธีการที่ดีจะช่วยได้

ด้วยที่กล่าวไว้ด้านล่างนี้เป็นฟังก์ชั่นการอธิบายการ debounce พื้นฐานและสาธิตในโพสต์ของฉันที่อ้างถึงข้างต้น

ผลิตภัณฑ์สำเร็จรูป

// Create JD Object
// ----------------
var JD = {};

// Debounce Method
// ---------------
JD.debounce = function(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this,
            args = arguments;
        var later = function() {
            timeout = null;
            if ( !immediate ) {
                func.apply(context, args);
            }
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait || 200);
        if ( callNow ) { 
            func.apply(context, args);
        }
    };
};

คำอธิบาย

// Create JD Object
// ----------------
/*
    It's a good idea to attach helper methods like `debounce` to your own 
    custom object. That way, you don't pollute the global space by 
    attaching methods to the `window` object and potentially run in to
    conflicts.
*/
var JD = {};

// Debounce Method
// ---------------
/*
    Return a function, that, as long as it continues to be invoked, will
    not be triggered. The function will be called after it stops being 
    called for `wait` milliseconds. If `immediate` is passed, trigger the 
    function on the leading edge, instead of the trailing.
*/
JD.debounce = function(func, wait, immediate) {
    /*
        Declare a variable named `timeout` variable that we will later use 
        to store the *timeout ID returned by the `setTimeout` function.

        *When setTimeout is called, it retuns a numeric ID. This unique ID
        can be used in conjunction with JavaScript's `clearTimeout` method 
        to prevent the code passed in the first argument of the `setTimout`
        function from being called. Note, this prevention will only occur
        if `clearTimeout` is called before the specified number of 
        milliseconds passed in the second argument of setTimeout have been
        met.
    */
    var timeout;

    /*
        Return an anomymous function that has access to the `func`
        argument of our `debounce` method through the process of closure.
    */
    return function() {

        /*
            1) Assign `this` to a variable named `context` so that the 
               `func` argument passed to our `debounce` method can be 
               called in the proper context.

            2) Assign all *arugments passed in the `func` argument of our
               `debounce` method to a variable named `args`.

            *JavaScript natively makes all arguments passed to a function
            accessible inside of the function in an array-like variable 
            named `arguments`. Assinging `arguments` to `args` combines 
            all arguments passed in the `func` argument of our `debounce` 
            method in a single variable.
        */
        var context = this,   /* 1 */
            args = arguments; /* 2 */

        /*
            Assign an anonymous function to a variable named `later`.
            This function will be passed in the first argument of the
            `setTimeout` function below.
        */
        var later = function() {

            /*      
                When the `later` function is called, remove the numeric ID 
                that was assigned to it by the `setTimeout` function.

                Note, by the time the `later` function is called, the
                `setTimeout` function will have returned a numeric ID to 
                the `timeout` variable. That numeric ID is removed by 
                assiging `null` to `timeout`.
            */
            timeout = null;

            /*
                If the boolean value passed in the `immediate` argument 
                of our `debouce` method is falsy, then invoke the 
                function passed in the `func` argument of our `debouce`
                method using JavaScript's *`apply` method.

                *The `apply` method allows you to call a function in an
                explicit context. The first argument defines what `this`
                should be. The second argument is passed as an array 
                containing all the arguments that should be passed to 
                `func` when it is called. Previously, we assigned `this` 
                to the `context` variable, and we assigned all arguments 
                passed in `func` to the `args` variable.
            */
            if ( !immediate ) {
                func.apply(context, args);
            }
        };

        /*
            If the value passed in the `immediate` argument of our 
            `debounce` method is truthy and the value assigned to `timeout`
            is falsy, then assign `true` to the `callNow` variable.
            Otherwise, assign `false` to the `callNow` variable.
        */
        var callNow = immediate && !timeout;

        /*
            As long as the event that our `debounce` method is bound to is 
            still firing within the `wait` period, remove the numerical ID  
            (returned to the `timeout` vaiable by `setTimeout`) from 
            JavaScript's execution queue. This prevents the function passed 
            in the `setTimeout` function from being invoked.

            Remember, the `debounce` method is intended for use on events
            that rapidly fire, ie: a window resize or scroll. The *first* 
            time the event fires, the `timeout` variable has been declared, 
            but no value has been assigned to it - it is `undefined`. 
            Therefore, nothing is removed from JavaScript's execution queue 
            because nothing has been placed in the queue - there is nothing 
            to clear.

            Below, the `timeout` variable is assigned the numerical ID 
            returned by the `setTimeout` function. So long as *subsequent* 
            events are fired before the `wait` is met, `timeout` will be 
            cleared, resulting in the function passed in the `setTimeout` 
            function being removed from the execution queue. As soon as the 
            `wait` is met, the function passed in the `setTimeout` function 
            will execute.
        */
        clearTimeout(timeout);

        /*
            Assign a `setTimout` function to the `timeout` variable we 
            previously declared. Pass the function assigned to the `later` 
            variable to the `setTimeout` function, along with the numerical 
            value assigned to the `wait` argument in our `debounce` method. 
            If no value is passed to the `wait` argument in our `debounce` 
            method, pass a value of 200 milliseconds to the `setTimeout` 
            function.  
        */
        timeout = setTimeout(later, wait || 200);

        /*
            Typically, you want the function passed in the `func` argument
            of our `debounce` method to execute once *after* the `wait` 
            period has been met for the event that our `debounce` method is 
            bound to (the trailing side). However, if you want the function 
            to execute once *before* the event has finished (on the leading 
            side), you can pass `true` in the `immediate` argument of our 
            `debounce` method.

            If `true` is passed in the `immediate` argument of our 
            `debounce` method, the value assigned to the `callNow` variable 
            declared above will be `true` only after the *first* time the 
            event that our `debounce` method is bound to has fired.

            After the first time the event is fired, the `timeout` variable
            will contain a falsey value. Therfore, the result of the 
            expression that gets assigned to the `callNow` variable is 
            `true` and the function passed in the `func` argument of our
            `debounce` method is exected in the line of code below.

            Every subsequent time the event that our `debounce` method is 
            bound to fires within the `wait` period, the `timeout` variable 
            holds the numerical ID returned from the `setTimout` function 
            assigned to it when the previous event was fired, and the 
            `debounce` method was executed.

            This means that for all subsequent events within the `wait`
            period, the `timeout` variable holds a truthy value, and the
            result of the expression that gets assigned to the `callNow`
            variable is `false`. Therefore, the function passed in the 
            `func` argument of our `debounce` method will not be executed.  

            Lastly, when the `wait` period is met and the `later` function
            that is passed in the `setTimeout` function executes, the 
            result is that it just assigns `null` to the `timeout` 
            variable. The `func` argument passed in our `debounce` method 
            will not be executed because the `if` condition inside the 
            `later` function fails. 
        */
        if ( callNow ) { 
            func.apply(context, args);
        }
    };
};

1

สิ่งที่คุณต้องการทำมีดังต่อไปนี้: ถ้าคุณพยายามเรียกใช้ฟังก์ชันหลังจากนั้นฟังก์ชันแรกควรถูกยกเลิกและรายการใหม่ควรรอให้หมดเวลาที่กำหนดและดำเนินการ ดังนั้นคุณต้องมีวิธียกเลิกการหมดเวลาของฟังก์ชันแรกใช่ไหม แต่อย่างไร คุณสามารถเรียกใช้ฟังก์ชันและส่งผ่าน timeout-id ที่ส่งคืนแล้วส่ง ID นั้นไปยังฟังก์ชันใหม่ใด ๆ แต่การแก้ปัญหาข้างต้นเป็นวิธีที่สง่างามมากขึ้น

มันทำอะไรได้อย่างมีประสิทธิภาพทำให้timeoutตัวแปรมีอยู่ในขอบเขตของฟังก์ชันที่ส่งคืน ดังนั้นเมื่อเหตุการณ์ 'ปรับขนาด' ถูกเปิดใช้งานจะไม่เรียกdebounce()อีกครั้งดังนั้นtimeoutเนื้อหาจะไม่เปลี่ยนแปลง (!) และยังคงพร้อมใช้งานสำหรับ "การเรียกใช้ฟังก์ชันถัดไป"

สิ่งสำคัญที่นี่คือพื้นที่เราเรียกฟังก์ชันภายในทุกครั้งที่เรามีเหตุการณ์ปรับขนาด บางทีมันอาจชัดเจนกว่านี้ถ้าเราจินตนาการว่าการปรับขนาดทั้งหมดนั้นอยู่ในอาร์เรย์:

var events = ['resize', 'resize', 'resize'];
var timeout = null;
for (var i = 0; i < events.length; i++){
    if (immediate && !timeout) func.apply(this, arguments);
    clearTimeout(timeout); // does not do anything if timeout is null.
    timeout = setTimeout(function(){
        timeout = null;
        if (!immediate) func.apply(this, arguments);
    }
}

คุณเห็นว่าtimeoutมีอยู่ในการทำซ้ำครั้งถัดไปหรือไม่ และไม่มีเหตุผลในความคิดของฉันที่จะเปลี่ยนชื่อthisไปcontentและจะargumentsargs


"การเปลี่ยนชื่อ" เป็นสิ่งที่จำเป็นอย่างยิ่ง ความหมายของthisและargumentsการเปลี่ยนแปลงภายในฟังก์ชั่นการโทรกลับ setTimeout () คุณต้องเก็บสำเนาไว้ที่อื่นหรือข้อมูลนั้นหายไป
CubicleSoft

1

นี่คือรูปแบบที่มักจะเรียกฟังก์ชั่น debounce ในครั้งแรกที่มันถูกเรียกด้วยตัวแปรที่มีคำอธิบายมากกว่า:

function debounce(fn, wait = 1000) {
  let debounced = false;
  let resetDebouncedTimeout = null;
  return function(...args) {
    if (!debounced) {
      debounced = true;
      fn(...args);
      resetDebouncedTimeout = setTimeout(() => {
        debounced = false;
      }, wait);
    } else {
      clearTimeout(resetDebouncedTimeout);
      resetDebouncedTimeout = setTimeout(() => {
        debounced = false;
        fn(...args);
      }, wait);
    }
  }
};

1

วิธีการแก้ปัญหาอย่างง่ายใน javascript

<!-- Basic HTML -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Debounce Method</title>
</head>
<body>
  <button type="button" id="debounce">Debounce Method</button><br />
  <span id="message"></span>
</body>
</html>

  // JS File
  var debouncebtn = document.getElementById('debounce');
    function debounce(func, delay){
      var debounceTimer;
      return function () {
        var context = this, args = arguments;
        clearTimeout(debounceTimer);
        debounceTimer = setTimeout(function() {
          func.apply(context, args)
        }, delay);
      }
    }

// Driver Code
debouncebtn.addEventListener('click', debounce(function() {
    document.getElementById('message').innerHTML += '<br/> Button only triggeres is every 3 secounds how much every you fire an event';
  console.log('Button only triggeres in every 3 secounds how much every you fire an event');
},3000))

ตัวอย่างรันไทม์ JSFiddle: https://jsfiddle.net/arbaazshaikh919/d7543wqe/10/


0

ฟังก์ชั่น debounce อย่างง่าย: -

HTML: -

<button id='myid'>Click me</button>

javascript: -

    function debounce(fn, delay) {
      let timeoutID;
      return function(...args){
          if(timeoutID) clearTimeout(timeoutID);
          timeoutID = setTimeout(()=>{
            fn(...args)
          }, delay);
      }
   }

document.getElementById('myid').addEventListener('click', debounce(() => {
  console.log('clicked');
},2000));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.