Underscore debounce vs vanilla Javascript setTimeout
Asked Answered
T

5

26

I understand that debounce in Undercore.js returns a function that will postpone its execution until the wait time is over.

My question is, is there an advantage of using debounce over the regular setTimeout function in vanilla Javascript? Don't they both work the same?

Tzar answered 11/4, 2016 at 12:16 Comment(1)
They are significantly different. I suggest you reread the documentation: underscorejs.org/#debounce (and note that debounce uses setTimeout under the hood)Pleasure
P
20

They are very different and used in completely different cases.

  1. _.debounce returns a function, setTimeout returns an id which you can use to cancel the timeOut.

  2. No matter how many times you call the function which is returned by _.debounce, it will run only once in the given time frame.

var log_once = _.debounce(log, 5000);

function log() {
  console.log('prints');
}

log_once();
log_once();
log_once();
log_once();
log_once();

var id = setTimeout(function() {
  console.log('hello');
}, 3000);
clearTimeout(id);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
Phonemic answered 11/4, 2016 at 12:50 Comment(1)
Just FYI, This Vanilla debounce method returns the Timeout so you can cancel it manually if you choose too.Portis
D
12

setTimeout and debounce are in no way the same thing. setTimeout simply waits n milliseconds and the invokes the supplied function. debounce on the other hand returns a function that only calls the callback after n milliseconds after the last time the functions was called.

Huge difference. Debouncing/throttling (they are not the same thing) functions are often used to reduced the amount of function calls as a result of user input. Imagine a autocomplete/typeahead field. You might do an ajax request every keystroke, but that can get kind of heavy, so instead you can debounce the function, so it will only fire 200ms after the last keystroke.

You can read up on the documentation here: https://lodash.com/docs#debounce

Disembogue answered 11/4, 2016 at 12:33 Comment(2)
...unless your event handler first cancels the timeout and then resets it. Then, you effectively have the same behavior.Chandrachandragupta
you can achieve the debounce functionality with setTimeout and clearTimeout. You assign the setTimeout into a variable and use clearTimeout above the variable declaration. let timer; function SetTimer(){ clearTimeout(timer); // the clearTimeout will work if timer hs been assign before timer = setTimeout(() => console.log("here"), 1000); };Psychokinesis
M
11

You can also implement your own debounce in vanilla JavaScript. A widely quoted article is David Walsh's article on function debouncing with underscore which includes the source code used by underscore in their implementation:

// 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. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
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);
    };
};

The debounce function serves as a generator for the actual function you'd like to call, that way the state can be persisted inside of the closure like this:

// example function
let sayHello = (name) => console.log(`Hi ${name}`)

// generate a debounced version with a min time between calls of 2 seconds
let sayHelloDebounced = debounce(sayHello, 2000)

// call however you want
sayHelloDebounced('David')

Demo in Stack Snippets

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

let sayHello = (name) => console.log(`Hi ${name}`)

let sayHelloDebounced = debounce(sayHello, 2000)

sayHelloDebounced('David')
sayHelloDebounced('David')
sayHelloDebounced('David')

Other Implementations

Mistassini answered 16/4, 2020 at 2:14 Comment(0)
P
0

setTimeout will run once after n seconds passed. So if you call setTimeout 4 times, it will run 4 times. Debounce on the other hand it will be called only once. enter image description here

In formal English debounce does what setTimeout and clearTiemout do together. If you don't want to use debounce you can use setTimeout together with clearTiemout to achieve the same behavior.

let timer; 
function setTimer(){ 
  clearTimeout(timer); 
  timer = setTimeout(() => console.log("here"), 1000); 
};
setTimer();
setTimer();
setTimer();
setTimer();
// here

enter image description here

Psychokinesis answered 28/11, 2023 at 14:5 Comment(0)
K
-1

I came across a blog post which has much clearer explanation on debounce and throttle. Do check it out if above answers seems confusing. It helped me clear my doubts. Debounce and Throttle in Javascript

Kremlin answered 8/5, 2020 at 19:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.