Can someone explain the “debounce” function in Javascript

后端 未结 8 831
旧时难觅i
旧时难觅i 2020-11-22 02:57

I am interested in the \"debouncing\" function in javascript, written here : http://davidwalsh.name/javascript-debounce-function

Unfortunately the code is not explai

相关标签:
8条回答
  • 2020-11-22 03:13

    This is a variation which always fires the debounced function the first time it is called, with more descriptively named variables:

    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);
        }
      }
    };
    
    0 讨论(0)
  • 2020-11-22 03:18

    Simple debounce function :-

    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));
    
    0 讨论(0)
  • 2020-11-22 03:22

    Simple Debounce method in 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))
    

    Runtime Example JSFiddle: https://jsfiddle.net/arbaazshaikh919/d7543wqe/10/

    0 讨论(0)
  • 2020-11-22 03:25

    Debounced functions do not execute when invoked, they wait for a pause of invocations over a configurable duration before executing; each new invocation restarts the timer.

    Throttled functions execute and then wait a configurable duration before being eligible to fire again.

    Debounce is great for keypress events; when the user starts typing and then pauses you submit all the key presses as a single event, thus cutting down on the handling invocations.

    Throttle is great for realtime endpoints that you only want to allow the user to invoke once per a set period of time.

    Check out Underscore.js for their implementations too.

    0 讨论(0)
  • 2020-11-22 03:25

    What you want to do is the following: If you try to call a function right after another, the first should be cancelled and the new one should wait for a given timeout and then execute. So in effect you need some way of cancelling the timeout of the first function? But how? You could call the function, and pass the returning timeout-id and then pass that ID into any new functions. But the solution above is way more elegant.

    What it does is effectively make the timeout variable available in the scope of returned function. So when a 'resize' event is fired it does not call debounce() again, hence the timeout content is not changed (!) and still available for the "next function call".

    The key thing here is basically that we call the internal function every time we have a resize event. Perhaps it is more clear if we imagine all resize-events is in an array:

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

    You see the timeout is available to the next iteration? And there is no reason, in my opinion to rename this to content and arguments to args.

    0 讨论(0)
  • The important thing to note here is that debounce produces a function that is "closed over" the timeout variable. The timeout variable stays accessible during every call of the produced function even after debounce itself has returned, and can change over different calls.

    The general idea for debounce is the following:

    1. Start with no timeout.
    2. If the produced function is called, clear and reset the timeout.
    3. If the timeout is hit, call the original function.

    The first point is just var timeout;, it is indeed just undefined. Luckily, clearTimeout is fairly lax about its input: passing an undefined timer identifier causes it to just do nothing, it doesn't throw an error or something.

    The second point is done by the produced function. It first stores some information about the call (the this context and the arguments) in variables so it can later use these for the debounced call. It then clears the timeout (if there was one set) and then creates a new one to replace it using setTimeout. Note that this overwrites the value of timeout and this value persists over multiple function calls! This allows the debounce to actually work: if the function is called multiple times, timeout is overwritten multiple times with a new timer. If this were not the case, multiple calls would cause multiple timers to be started which all remain active - the calls would simply be delayed, but not debounced.

    The third point is done in the timeout callback. It unsets the timeout variable and does the actual function call using the stored call information.

    The immediate flag is supposed to control whether the function should be called before or after the timer. If it is false, the original function is not called until after the timer is hit. If it is true, the original function is first called and will not be called any more until the timer is hit.

    However, I do believe that the if (immediate && !timeout) check is wrong: timeout has just been set to the timer identifier returned by setTimeout so !timeout is always false at that point and thus the function can never be called. The current version of underscore.js seems to have a slightly different check, where it evaluates immediate && !timeout before calling setTimeout. (The algorithm is also a bit different, e.g. it doesn't use clearTimeout.) That's why you should always try to use the latest version of your libraries. :-)

    0 讨论(0)
提交回复
热议问题