Skip to content Skip to sidebar Skip to footer

How To Synchronously Declare Js Object And Then Edit A Property Of The Object With Data That Is Dependent On A Concurrent Operation

I'm parsing data returned from Eventbrite's API, and forming objects from the name of the event and any img tags scraped from the entirety of data response. for (var i = 1, l = raw

Solution 1:

This is the classic closure problem. The function you're passing as the done handler has an enduring reference to the eventObject variable (and there's only one, it's not loop-specific), so only the last one gets filled in. (This is usually what you want, but not in this case.)

You can work around it with a builder function that closes over something else (usually an argument):

for (var i = 1, l = rawEventbriteData.length; i < l; i++){

    var eventObject = {
        name: rawEventbriteData[i].event.title,
        images: []
    };

    var jsdom = require('jsdom');
    var arrayOfImgs = [];
    jsdom.env({
        html: rawEventbriteData[i].event.description,
        scripts: ["http://code.jquery.com/jquery.js"],
        done: buildDoneHandler(eventObject)
    });

}

functionbuildDoneHandler(evtobj) {
    returnfunction(errors, window) {
        window.$('img').each(function(){
            var imgSrc = window.$(this).attr('src');
            console.log(imgSrc);
            evtobj.images.push(imgSrc);
        });
    };
}

Note that the functon returned by buildDoneHandler closes over and uses evtobj (the argument we give buildDoneHanlder) rather than eventObject. Since the argument is specific to each call to buildDoneHandler, we update the right event object.

This can also be done with ES5's Function#bind although it can get confusing when there are other arguments, and creating functions that you bind in a loop is wasteful (not that it usually matters):

for (var i = 1, l = rawEventbriteData.length; i < l; i++){

    var eventObject = {
        name: rawEventbriteData[i].event.title,
        images: []
    };

    var jsdom = require('jsdom');
    var arrayOfImgs = [];
    jsdom.env({
        html: rawEventbriteData[i].event.description,
        scripts: ["http://code.jquery.com/jquery.js"],
        done: function(evtobj, errors, window) {
            window.$('img').each(function(){
                var imgSrc = window.$(this).attr('src');
                console.log(imgSrc);
                evtobj.images.push(imgSrc);
            });
        }.bind(null, eventObject)
    });
}

Function#bind returns a function that, when called, will call the original function with a specific this value and with any further arguments you give it at the beginning of the arguments list.

Post a Comment for "How To Synchronously Declare Js Object And Then Edit A Property Of The Object With Data That Is Dependent On A Concurrent Operation"