Aleksandr
Aleksandr

Reputation: 437

Incomprehensible work decorator function

Is a function:

var f = function(a) { console.log(a) };

function throttle(func, ms) {
    var stop = false, savedThis, savedArgs;

    return function wrapper() {
        if(stop) {
            savedArgs = arguments;
            savedThis = this;
            return;
        } 

        func.apply(this, arguments)
        stop = true;

        setTimeout(function() {
            stop = false;
            if(savedArgs) {
                wrapper.apply(savedThis, savedArgs);
                savedArgs = savedThis = null;
            }
        }, ms);
    };
}

// brake function to once every 1000 ms
var f1000 = throttle(f, 1000);

f1000(1); // print 1
f1000(2); // (brakes, less than 1000ms)
f1000(3); // (brakes, less than 1000ms)

The first call f1000 (1) displays 1. f1000 (2), the second call does not work, but it will keep in savedAggs link to the arguments of the second call. The third launch also does not work, but it will overwrite the link to the arguments of the third call. Through 1000 ms setTimeout cause an anonymous function, the variable will stop within the meaning of the false. Condition of work, and the wrapper will be called recursively. But then I can not understand what's going on? When this code works: savedArgs = savedThis = null;?

Upvotes: 1

Views: 68

Answers (1)

Bergi
Bergi

Reputation: 664548

The function is a bit incomprehensible, yes. Its job is to throttle the rate of invocations to at most one per 1000 ms - however if they occur more frequent, it will also repeat the last invocation as soon as the timeout has finished.

It might better be written

function throttle(func, ms) {
    var stop = false, savedThis, savedArgs;
    function invoke() {
        stop = true; // the last invocation will have been less than `ms` ago
        func.apply(savedThis, savedArgs);
        savedThis = savedArgs = null;
        setTimeout(function() {
            stop = false; // the timeout is over, start accepting new invocations
            if (savedArgs) // there has been at least one invocation during
                           // the current timeout
                invoke();  // let's repeat that
        }, ms);
    }
    return function wrapper() {
        savedArgs = arguments;
        savedThis = this;

        if (stop)
            return;
        else
            invoke();
    };
}

Upvotes: 2

Related Questions