使用jQuery的动态AJAX承诺链

Chr*_*ris 15 javascript ajax jquery chaining promise

我的AJAX调用是在for循环中构建的.它们需要按顺序(同步).我如何用jQuery链接它们?

var array = ['One', 'Two', 'Three'];
var arrayLength = array.length;
for (var arrayCounter = 0; arrayCounter < arrayLength; arrayCounter++) {
    var id = array[arrayCounter];
    getData(id);

    function getData(id) {
        $.ajax({
            url: 'http://example.com/' + id,
            dataType: 'jsonp',
            success: function(d) {
                var response = d;
                console.log(d);
            },
            error: function() {
                alert("ERROR");
            }
        });
    }
}   
Run Code Online (Sandbox Code Playgroud)

Flo*_*ine 13

解决方案使用for:

var array = ['One', 'Two', 'Three'];
var id = array[0];
var data = getData(id);
for (var i = 1; i < array.length; i++) {
    // Or only the last "i" will be used
    (function (i) {
        data = data.then(function() {
            return getData(array[i]);
        });
    }(i));
}

// Also, see how better the getData can be.
function getData(id) {
    return $.ajax({
        url: 'http://example.com/' + id,
        dataType: 'jsonp',
    }).done(function(d) {
        var response = d;
        console.log(d);
    }).fail(function() {
        alert('ERROR');
    });
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果你使用了正确的promises库,比如bluebird,你将使用以下代码:

var array = ['One', 'Two', 'Three'];
Promise.reduce(array, function(data, id) {
    return data.promise.then(function(result) {
        return { promise: getData(id), results: data.results.push(result) };
    });
}, []).then(function(data) {
    console.log(data.results); // yay!
});

function getData(id) {
    return Promise.cast($.ajax({
        url: 'http://example.com/' + id,
        dataType: 'jsonp',
    }).done(function(d) {
        var response = d;
        console.log(d);
    }).fail(function() {
        alert('ERROR');
    }));
}
Run Code Online (Sandbox Code Playgroud)

如您所见,更容易读/写.


Ben*_*aum 11

大多数promise库都内置了jQuery吗?不太幸运:

首先,你的函数应该返回一个promise:

 function getData(id) {
        return $.ajax({ // note the return
            url: 'http://example.com/'+id,
            dataType: 'jsonp',
            success: function (d) {
                console.log(d);
            },
            error: function () {
                alert("ERROR")
            }
        });
}
Run Code Online (Sandbox Code Playgroud)

现在,您使用.then调用将它们链接在一个循环中.请注意,.then只有在前一个承诺完成后才会执行.因此,他们将一个接一个地按顺序运行.

var array = ['One', 'Two', 'Three'];
var p = $.when(1); // empty promise
array.forEach(function(el){
    p = p.then(function(){
        return getData(el);;
    });
});
Run Code Online (Sandbox Code Playgroud)

所有功能将一个接一个地运行.还剩什么?返回值.当前实现丢弃返回值.我们可以将返回值放在一个数组中,例如:

var array = ['One', 'Two', 'Three'];
var p = $.when(1); // empty promise
var results = [];
array.forEach(function(el,index){
    p = p.then(function(){
        return getData(el);
    }).then(function(data){
        results[index] = data; // save the data
    });
});
p.then(function(){
    // all promises done, results contains the return values
});
Run Code Online (Sandbox Code Playgroud)

为什么要停在那里,让它更好:)你的整个代码可以缩短为

["One","Two","Three"].map(makeUrl).map($.get).reduce(function(prev,cur,idx){
    return prev.then(cur).then(function(data){ results[idx] = data; });
},$.when(1)).then(function(){
   // results contains all responses here, all requests are sync
});

function makeUrl(id){
    return "http://example.com"+id+"?callback=?";
}
Run Code Online (Sandbox Code Playgroud)