简体   繁体   中英

jQuery: functions in array for when() done() are called immediately

I'm trying to push some Javascript functions into an array to call them with jQuery.when() but when doing so, the functions are already called when put into the array. Here's an example and here's my code snippet:

    var answers = someJSONFormattedData;
    var calls = [];

    function callWithIndex(i) {
        var answer = answers[i];
         api.loadUser(answer.userType, answer.userId, function(userData) {               
             answer.user = userData;
         }, null)
    };


    for(var i=0;i<answers.length;++i) {
        calls.push(callWithIndex(i));
    }


     $.when.apply($, calls).then(function() {
         var dataAsJSON = {
                 'answers': answers
         };
         //do some magic stuff with dataAsJSON           
     });

Even when doing a short test code snippet, the test() function is called immediately although I wouldn't it to be called at all as I only put it into an array (or at least try to).

var test = function(i) {
    console.log("test: "+i);
}

var testArray = [];
for(var i=0;i<5;++i) {
    testArray.push(test(i));
}

You need to push a reference to the function, not to its ( undefined ) results:

Try this:

calls.push(callWithIndex.bind(null, i));

First of all, thanks to everybody, but it turned out that the problem was something else. The problem was not that the functions in the array were called immediatly but that the done() function was executed before the ajax calls within the callWithIndex function were finished.

The right way to achieve that the done is invoked after the functions in the array have finished is to let the passed functions return the return value of its inner ajax() call (which in my case is wrapped in api.loadUser).

As far as I understood, a jQuery's ajax call returns a Deferred object and the done() function is invoked as soon as all Deferred objects that were passed in the when() function finished. Imho, this is not really well documented in the jQuery documentation, where they simply use ajax() calls without mentioning that the return value does the trick here.

Here you'll find a nice Tutorial about jQuery when(...)done(...) stuff


So in the end, my code looks as follows:

In my api namespace i define the loadUser function which now returns the ajax return value

api.loadUser = function(userType, userId, onSuccess, onError) {
    return $.ajax({
         //do your ajax stuff
    });
};

In my current JavaScript file it now looks as follows:

    var collectedData = [];
    var callWithIndex = function(i, userType, userId) {
        return api.loadUser(userType, userId, function(data) {
            collectedData.push(data);
        });
    }

    var deferreds = [];
    for(var i=0;i<someData.length;++i) {
        var entry = someData[i];
        deferreds.push(callWithIndex(i, entry.userType, entry.userId));
    }



    $.when.apply($, deferreds).done(function(result) {
         // do stuff with collectedData
    });

This worked for me so far and now the done() is invoked when all callWithIndex calls are done.

The reason I did not use

        deferreds.push(api.loadUser(answer.userType, answer.userId, function(data) {
            //do stuff with collectedData 
        }));

was that the collectedData array is undefined for the success function of loadUser(). I guess this is some scope related issue, but I don't care.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM