debounce icon indicating copy to clipboard operation
debounce copied to clipboard

Optimized version

Open stevensacks opened this issue 8 years ago • 1 comments

Hello! Thanks for your nice and clean debounce function. Lodash's is powerful but overly complicated for most use. I optimized your code and also wrote it for ES6.

  1. You only need timeout to be outside the returned closure. The rest of the vars can go inside.
  2. You can use Date.now() instead of new Date().
  3. You don't need to save the context for the func.apply(), you can just pass null.
  4. You can use a ternary to return an IIFE which returns nothing to set the timeout variable to undefined.

ES5

var debounce = function(wait, func) { 
    var timeout;
    return function() {
        var last, 
            args = [].slice.call(arguments, 0), 
            timestamp = Date.now(), 
            later = function() {
                last = Date.now() - timestamp,
                timeout = wait > last ? setTimeout(later, wait - last) : function() { func.apply(null, args); }();
            };
        timeout || (timeout = setTimeout(later, wait));
    }
};

In ES6, you can use the ...args operator instead of [].slice.call().

const debounce = (wait, func) => { 
    var timeout; 
    return (...args) => { 
        var last,
            timestamp = Date.now(), 
            later = () => { 
                last = Date.now() - timestamp;
                timeout = wait > last ? setTimeout(later, wait - last) : (() => { func.apply(null, args); })();
            };
        timeout || (timeout = setTimeout(later, wait));
    }
};

stevensacks avatar Jun 27 '16 03:06 stevensacks

I liked your optimized version, but it does not work. You have to move the timestamp (and args) up in the closure.

function debounceOpt(func: (...args: any[]) => void, wait: number) {
    var timeout, stampTest;
    return function () {
        var last;
        var args = [].slice.call(arguments, 0);
        var timestamp = stampTest = Date.now();

        var later = function () {
            console.log(timestamp - stampTest); // never 0
            last = Date.now() - stampTest, // This works, timestamp doesn't
                timeout = wait > last ? setTimeout(later, wait - last) : function () { func.apply(null, args); }();
        };
        timeout || (timeout = setTimeout(later, wait));
    }
};

I ended up with this:

function debounceOpt(func, wait) {
    var timeout, timestamp, args;
    function later() {
        var last = Date.now() - timestamp;
        console.log(last);
        timeout = wait > last ? setTimeout(later, wait - last) : (func.apply(null, args), null);
    };
    return function () {
        args = [].slice.call(arguments, 0);
        timestamp  = Date.now();
        timeout || (timeout = setTimeout(later, wait));
    }
};

kritollm avatar Dec 05 '20 13:12 kritollm