jQuery:数组中的函数立即调用when()done()

时间:2015-01-21 10:07:52

标签: javascript jquery arrays asynchronous

我正在尝试将一些Javascript函数推送到数组中以使用jQuery.when()调用它们,但是当这样做时,函数在放入数组时已经被调用。 Here's an example这是我的代码段:

    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           
     });

即使在做一个简短的测试代码片段时,也会立即调用test()函数,尽管我根本不会调用它,因为我只将它放入一个数组中(或至少尝试)。

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

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

2 个答案:

答案 0 :(得分:5)

您需要push对该函数的引用,而不是其(undefined)结果的引用:

试试这个:

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

答案 1 :(得分:0)

首先,感谢所有人,但事实证明问题是另一回事。问题不在于数组中的函数是立即调用的,而是在callWithIndex函数中的ajax调用完成之前执行了done()函数。

在数组中的函数完成后调用done的正确方法是让传递的函数返回其内部ajax()调用的返回值(在我的例子中)包装在api.loadUser中)。

据我所知,jQuery的ajax调用返回一个Deferred对象,并且只要在when()函数中传递的所有Deferred对象都完成,就会调用done()函数。 Imho,这在jQuery文档中并没有很好地记录,他们只是使用ajax()调用,而没有提到返回值在这里诀窍。

Here你会找到一个很好的关于jQuery的教程(...)完成(...)的东西


所以最后,我的代码如下:

在我的api命名空间中,我定义了loadUser函数,该函数现在返回ajax返回值

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

在我目前的JavaScript文件中,它现在看起来如下:

    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
    });

到目前为止,这对我有用,现在在完成所有callWithIndex调用时调用done()。

我没有使用的原因

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

是对于loadUser()的成功函数未定义的collectData数组。我想这是与范围相关的问题,但我不在乎。