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

ner*_*daj 0 ajax jquery 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      
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

jfr*_*d00 8

你在这里的日志声明:

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

永远不会发生,因为它是在return发表声明之后.

也许你想回def.promise()loginUser().但是,唉,根本没有理由创造这种额外的延期. $.when()已经返回一个可以这种方式使用的promise.


这是我认为你可能真正想要的东西:

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
});
Run Code Online (Sandbox Code Playgroud)

或者,正如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
});
Run Code Online (Sandbox Code Playgroud)

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


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