延迟承诺AJAX循环then()永远不会发生

时间:2014-04-25 18:12:56

标签: jquery ajax promise deferred

我试图在AJAX循环中使用延迟的promise,因为使用async:false会锁定页面。我已经开始讨论其他类似用途,但我不明白为什么$ .when()。apply()。then()永远不会执行。

    var userData = {};  
    userData.user1 = {"creds":{"userid":"user1@test.com","password":"user1pass","country":"us"}};
    userData.user2 = {"creds":{"userid":"user2@test.com","password":"user2pass","country":"mx"}};
    userData.user3 = {"creds":{"userid":"user3@test.com","password":"user3pass","country":"ca"}};
    function loginUser(credentials){
        var def = new $.Deferred();
        requests = [];
        $.each(credentials, function(k, v){
            var promise = $.ajax({
                url : '/path/to/my/uri', 
                type : 'post',
                contentType : 'application/json',
                data : JSON.stringify(v)
            });
            requests.push(promise); 
        });
        console.log(requests);
        // check if all ajax calls have finished
        $.when.apply($, requests).then(function() {
            // this never happens
            def.resolve();
            return def.promise();
            console.log('the request is done');
        });
    }
    loginUser(userData);


//updated snippet
var userData = {};  
userData.user1 = {"creds":{"userid":"user1@test.com","password":"user1pass","country":"us"}};
userData.user2 = {"creds":{"userid":"user2@test.com","password":"user2pass","country":"mx"}};
userData.user3 = {"creds":{"userid":"user3@test.com","password":"user3pass","country":"ca"}};
function loginUser(credentials){
    var requests = $.map(credentials, function(k, v){
    return $.ajax({
            url : '/path/to/my/uri', 
            type : 'post',
            contentType : 'application/json',
            data : JSON.stringify(k)
        });
    });
    console.log(requests);
    // return a promise that will resolve when all ajax calls are done
    return $.when.apply($, requests);
}

loginUser(userData).done(function() {
// all logins completed here
console.log('inside done');
}).fail(function() {
// will be called if any login failed
console.log('inside fail');
});

// current syncronous functionality
function loadUrls(credentials){
    $.each(credentials, function(k, v){
        $.ajax({
            url : '/path/to/my/uri', 
            type : 'post',
            contentType : 'application/json',
            success: function(data, textStatus, jqXHR) {
                $('body').append('<a target="_blank" href="'+data.userInfo+'">'+data.userName+' '+k+'</a><br />');
            },
            data : JSON.stringify(v),
            error : function(jqXHR, textStatus, errorThrown){
                return;                 
            },
            async : false      
        });
    });
}

1 个答案:

答案 0 :(得分:8)

您在此处的日志声明:

    $.when.apply($, requests).then(function() {
        // this never happens
        def.resolve();
        return def.promise();
        console.log('the request is done');
    });

永远不会发生,因为它正好在return声明之后。

也许您打算从def.promise()返回loginUser()。但是,唉,根本没有理由创造这种额外的延期。 $.when()已经返回了可以这种方式使用的承诺。


以下是我认为您可能真正想要的内容:

var userData = {};  
userData.user1 = {"creds":{"userid":"user1@test.com","password":"user1pass","country":"us"}};
userData.user2 = {"creds":{"userid":"user2@test.com","password":"user2pass","country":"mx"}};
userData.user3 = {"creds":{"userid":"user3@test.com","password":"user3pass","country":"ca"}};
function loginUser(credentials){
    var requests = [];
    $.each(credentials, function(k, v){
        var promise = $.ajax({
            url : '/path/to/my/uri', 
            type : 'post',
            contentType : 'application/json',
            data : JSON.stringify(v)
        });
        requests.push(promise); 
    });
    console.log(requests);
    // return a promise that will resolve when all ajax calls are done
    return $.when.apply($, requests);
}

loginUser(userData).done(function() {
   // all logins completed here
}).fail(function() {
   // will be called if any login failed
});

或者,正如Benjamin Gruenbaum建议的那样,您可以使用$.map()代替$.each()来缩短代码。

var userData = {};  
userData.user1 = {"creds":{"userid":"user1@test.com","password":"user1pass","country":"us"}};
userData.user2 = {"creds":{"userid":"user2@test.com","password":"user2pass","country":"mx"}};
userData.user3 = {"creds":{"userid":"user3@test.com","password":"user3pass","country":"ca"}};
function loginUser(credentials){
    var requests = $.map(credentials, function(k, v){
        return $.ajax({
            url : '/path/to/my/uri', 
            type : 'post',
            contentType : 'application/json',
            data : JSON.stringify(v)
        });
    });
    console.log(requests);
    // return a promise that will resolve when all ajax calls are done
    return $.when.apply($, requests);
}

loginUser(userData).done(function() {
   // all logins completed here
}).fail(function() {
   // will be called if any login failed
});

如果你所说的是你的$.when.done()处理程序从未被调用过(即使你将console.log()语句放在一个会被执行的地方),那么唯一的方法就是您的一个ajax调用未成功完成。除了.fail()处理程序之外,您还可以通过添加.done()处理程序来注意这一点。


如果您真正想要对多次登录做的事情就是要确定是否至少有一次登录成功(即使其他登录失败),那么您将需要不同的逻辑来检测该条件,因为{ {1}}只会告诉您所有承诺是否已解决或是否有任何承诺被拒绝。它不会告诉你是否至少有一个被接受。要做到这一点,我们必须知道如果登录被拒绝,ajax调用会发生什么。 ajax调用是否仍然成功,但结果显示登录失败?如果是这样,那么您必须检查传递给$.when()处理程序的数据,以查看是否至少有一次登录成功。