0

I was reading an article about requestAnimationFrame here, and I realized that I was having trouble following the scope and persistence of a variable. Slightly modified code below:

(function() {

    //Note: lastTime is defined up here.
    var lastTime = 0;

    var vendors = ['ms', 'moz', 'webkit', 'o'];

    //Okay, so they're trying to set window.rAF to the appropriate thing based on browser
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelRequestAnimationFrame = window[vendors[x]+
          'CancelRequestAnimationFrame'];
    }

    //...and if that doesn't work, turn it into a setTimeout
    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {

            //I guess this is a way to make sure that the wait time
            //between renders is consistent

            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 
              timeToCall);

            lastTime = currTime + timeToCall;

            //Wait. They just assigned lastTime a value.
            //Why is this going to persist between calls to window.rAF?
            //The variable lastTime was defined inside this function, not in the window.

            return id;
        };

    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}())

My guess is it has something to do with the function being placed inside parentheses, but how? What does this accomplish and what other effects can I expect with this coding style? Is this something I should start using more regularly, and if so, when?

1 Answer 1

3

The variable lastTime here is captured via closure. This means it is kept alive beyond the scope of the function it is defined in.

A closure gets created anytime an anonymous function body references a variable outside of its own scope. Closures are extremely useful in JavaScript, as they allow you to maintain state without exposing it all globally.

To give a simplified example,

function foo() {
    var count = 0;

    setInterval(function bar() {
        console.log(count++);
    }, 100);
}

By closing over the count variable here, I can use it in setInterval without exposing count to the global scope as I would otherwise have to do.

Sign up to request clarification or add additional context in comments.

2 Comments

Does this mean that window.requestAnimationFrame now has scope including the anonymous function? The thing I had in mind was as follows: (1) Global generally means inside the window object (2) This anonymous function exists in its own space because its variables cannot be accessed globally (3) By assigning the function to window.requestAnimationFrame, the function now exists in the window object, away from the anonymous function, and so it can't access the anonymous function's variables
Yes, all of these points are generally correct. For 3, it can only access the variables it has closed over. Variables are closed over when the callback function is defined; so your callback function couldn't, say, later on (via eval) try to grab another one of the anonymous function's variables, as it's already too late.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.