jQuery递归AJAX调用承诺

jQuery Recursive AJAX Call Promise

本文关键字:承诺 调用 AJAX 递归 jQuery      更新时间:2023-09-26

我仍在尝试如何在递归AJAX调用中使用jQuery延迟对象。我有一个类似的代码

function request(page, items){    
    //building the AJAX return value for JSFiddle dummy AJAX endpoint
    var ret = {
        totalPage: 10,
        currentPage: page,
        items: []
    };
    for (var i = page; i < (page + 5); i++){
        ret.items.push(i);
    }
    //calling the AJAX
    $.ajax({
        url: '/echo/json/',
        method: 'POST',
        dataType: 'json',
        data: {
            delay: 1,
            json: JSON.stringify(ret)
        },
        success: function(data){
            if (data.currentPage <= data.totalPage){
                var filtered = data.items.filter(function(el){
                    return el % 2 == 1;
                });
                var newitems = items.concat(filtered);
                console.dir(newitems);
                request(data.currentPage + 1, newitems);
            } else {
                console.dir(items);
                //resolve all item
            }
        }
    });
}
function requestAll(){
    request(1, []);
    //should return a promise tha contains all items
}

这是JSFiddlehttp://jsfiddle.net/petrabarus/BHswy/

我知道如何在单个AJAX调用中使用promise,但我不知道如何在递归AJAX调用中将其使用。我想用类似下面的方式调用requestAll函数

var promise = requestAll();
promise.done(function(items){
    console.dir(items);
});

我该怎么做?

如果要使用promise,则不应使用success参数。相反,您希望return是一个承诺,并且希望使用then将一个承诺的结果转换为不同的结果,甚至可能是另一个承诺。

function request(page) {    
    …
    // return the AJAX promise
    return $.ajax({
        url: '/echo/json/',
        method: 'POST',
        dataType: 'json',
        data: {
            delay: 1,
            json: JSON.stringify(ret)
        }
    });
}
function requestOddsFrom(page, items) {
    return request(page).then(function(data){
        if (data.currentPage > data.totalPage) {
            return items;
        } else {
            var filtered = data.items.filter(function(el){ return el%2 == 1; });
            return requestOddsFrom(data.currentPage + 1, items.concat(filtered));
        }
    });
}
function requestAll(){
    return requestOddsFrom(1, []);
}
requestAll().then(function(items) {
    console.dir(items);
});

由于您已经在一个接一个地对Ajax操作进行排序,而无需完全重新构造代码,因此您可以只使用上次Ajax调用中解决的一个延迟操作:

function request(page, items, defer){    
    //building the AJAX return value for JSFiddle dummy AJAX endpoint
    var ret = {
        totalPage: 10,
        currentPage: page,
        items: []
    };
    for (var i = page; i < (page + 5); i++){
        ret.items.push(i);
    }
    //calling the AJAX
    $.ajax({
        url: '/echo/json/',
        method: 'POST',
        dataType: 'json',
        data: {
            delay: 1,
            json: JSON.stringify(ret)
        },
        success: function(data){
            if (data.currentPage <= data.totalPage){
                var filtered = data.items.filter(function(el){
                    return el % 2 == 1;
                });
                var newitems = items.concat(filtered);
                console.dir(newitems);
                request(data.currentPage + 1, newitems, defer);
            } else {
                console.dir(items);
                //resolve the deferred
                defer.resolve(items);
            }
        }
    });
}
function requestAll(){
    var deferred = jQuery.Deferred();
    request(1, [], deferred);
    return deferred.promise();
}
requestAll().done(function(items) {
    // all ajax calls are done
});

好吧,经过大量新的promise学习,这里有一个使用promise链接(从.then()处理程序返回promise)的完全promise版本。从Benji的实现中借鉴和学习了一些概念,但它的组织方式有点不同,并对学习进行了评论(实际上,如果没有评论和伪Ajax调用,它会很短):

function requestPages(startPage, endPage) {
    function request(page, items){    
        // building the AJAX return value for 
        // JSFiddle dummy AJAX endpoint
        var ret = {
            currentPage: page,
            items: []
        };
        for (var i = page; i < (page + 5); i++){
            ret.items.push(i);
        }
        // Do Ajax call, return its promise
        return $.ajax({
            url: '/echo/json/',
            method: 'POST',
            dataType: 'json',
            data: {
                delay: 1,
                json: JSON.stringify(ret)
            }
        }).then(function(data) {
            // mock filter here to give us just odd values
            var filtered = data.items.filter(function(el){
                return el % 2 == 1;
            });
            // add these items to the ones we have so far
            items = items.concat(filtered);
            // if we have more pages to go, then do the next one
            if (page < endPage){
                // Advance the currentPage, call function to process it and
                // return a new promise that will be chained back to the 
                // promise that was originally returned by requestPages()
                return request(page + 1, items);
            } else {
                // Finish our iteration and 
                // return the accumulated items.
                // This will propagate back through 
                // all the other promises to the original promise
                // that requestPages() returned
                return(items);
            }
        });
    }    
    // call the first request and return it's promise    
    return request(startPage, []);
}
// request pages 1 through 10 inclusive
requestPages(1, 10).done(function(items) {
    // all ajax calls are done
    console.log(items);
});

工作jsFiddle:http://jsfiddle.net/jfriend00/pr5z9/(请耐心等待,执行10个Ajax调用需要10秒钟,每个调用需要1秒钟)。

我注意到这个版本的一个问题是,因为它只使用$.ajax()创建的promise,所以代码无法使用.notify()来触发进度通知。我发现我想在每次Ajax调用完成时,在最初返回的promise上触发一个进度通知,但如果没有创建自己的Deferred,我就无法做到这一点,因为你不能在promise上执行.notify(),只能在Deferred上执行。我不知道如何解决这个问题,并坚持Benji的架构,即不创建/解决您自己的延迟。