jQuery Recursive AJAX Call Promise

后端 未结 2 719
有刺的猬
有刺的猬 2020-12-06 02:11

I\'m still trying to figure out how to use jQuery deferred object in recursive AJAX call. I have a code like this

function request(page, items){    

    //b         


        
相关标签:
2条回答
  • 2020-12-06 02:53

    You should not use the success parameter if you want to work with promises. Instead, you want to return a promise, and you want to use then to transform the results of a promise into something different, possibly even another promise.

    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);
    });
    
    0 讨论(0)
  • 2020-12-06 02:57

    Since you're already sequencing the Ajax operations one after the other, without totally restructing your code, you can just use one deferred that you resolve on the last Ajax call:

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

    OK, after much new promise learning, here's a fully promise version that makes use of promise chaining (returning a promise from a .then() handler). Concepts borrowed and learned from Benji's implementation, but this is organized a bit differently and commented for learning (it would actually be quite short without comments and without the dummy Ajax call stuff):

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

    Working jsFiddle: http://jsfiddle.net/jfriend00/pr5z9/ (be patient, it takes 10 seconds to execute for 10 Ajax calls that each take 1 second).

    One issue I noticed about this version is that because it only uses the promises created by $.ajax(), the code cannot do a .notify() to trigger progress notifications. I found that I wanted to trigger a progress notification on the originally returned promise as each Ajax call completed, but without creating my own Deferred, I couldn't do that because you can't do a .notify() on a promise, only on a Deferred. I'm not sure how to solve that and keep with Benji's architecture of not creating/resolving your own deferred.

    0 讨论(0)
提交回复
热议问题