Search code examples
javascriptfor-loopclosuresmutable

Will an event that takes a long time to finish change the value of a "Mutable variable"


I have a large for loop (somewhere around 1000 iterations) in which an image URL from an object is loaded and, if it loads correctly, the object added to an array. My question is, because of the asynchronous nature of Javascript, if the image loading takes a long time, will the for loop continue iterating, and thus change the index value, and thus load the wrong item into the array. I get a warning from my editor that Mutable variable is accessible from closure in the following code:

function createArray(data){
    var entries = data['entries'];
    for (var k = 0, j = entries.length; k < j; k++) {
            if (entries[k].type = 'image') {
                var img = new Image();
                img.onload = function(){
                    validArray.push(entries[k]); //Here is where it is added to array. This [k] is the mutable value - wondering if the image takes a long time to load, if [k] will be incremented 
                };
                img.onerror = function(){
                    console.log('error: bad image source');
                };
                img.src = entries[k].url;
            } else {
                console.log('Not an image');
            }
        }
    }

Solution

  • The answer is yes, the variable k will likely have changed by the time the callback is executed. There is a simple solution though -- wrap the function in a closure. That way you can create a local copy of k, or more meaningfully, a local copy of entries[k]:

    img.onload = (function(entry) {
        return function(){
            validArray.push(entry); 
        };
    })(entries[k]);
    

    Or if you prefer to simplify the syntax, you can write a helper function like "getAddFunction":

    var getAddFunction = function(entry) {
        return function() {
            validArray.push(entry); 
        };
    };
    

    And then just:

    img.onload = getAddFunction(entries[k])