funguy
funguy

Reputation: 2160

Get outside variables into image.onload

I want to get image dimensions and afterwards perform more actions. As image onload is asynchronous I have decided to do everything in the onload call. This is what I have right now:

function getMeta(url, callback) {
    var img = new Image();
    img.src = url;
    img.onload = function() { callback(this.width, this.height); };
}

// ajax response this some info:

function(res) {
    var totalFound = res.data.length;
    var photo = [];

    for (var i = 0; i < totalFound; i++) {
        var full = res.data[i].urls.raw;
        var thumb = res.data[i].urls.thumb;
        var user = res.data[i].user.name;
        var links = res.data[i].user.links.html;

        getMeta(thumb,function(width, height) { 
            console.log(width + 'px ' + height + 'px') 

            photo.push({
                full: full,
                thumb: thumb,
                user: author,
                link: links
                width: this.width
            });
        });
    };
};

The problem is that variables full, thumb, user and links are not available in the getMeta callback. How to get over this?

Upvotes: 0

Views: 116

Answers (1)

Lennholm
Lennholm

Reputation: 7480

The problem is that those variables are scoped outside the for loop, meaning they're updated, rather than declared, in every successive iteration and every callback will see the final state of them since they're all invoked some time after the for loop has completed.

If you replace your for loop with a forEach, you will create a new scope for each iteration and the variables will be scoped the way you want them to:

function(res) {
    var photo = [];

    res.data.forEach(function(item) {
        var full = item.urls.raw;
        var thumb = item.urls.thumb;
        var user = item.user.name;
        var links = item.user.links.html;

        getMeta(thumb,function(width, height) { 
            console.log(width + 'px ' + height + 'px') 

            photo.push({
                full: full,
                thumb: thumb,
                user: author,
                link: links,
                width: this.width
            });
        });
    });
};

If you have the option of using ES6 syntax, an alternative is to simply use let instead of var which will properly scope the variables to each iteration.

Upvotes: 2

Related Questions