Chain ajax and execute it in sequence. Jquery Deferred

后端 未结 5 618
旧时难觅i
旧时难觅i 2020-11-30 02:53

I have 3 processes that needs ajax to complete. But it is asynchronous and it fails to do what I wanted to do..

Lets say:

function a(param1, param2)         


        
相关标签:
5条回答
  • 2020-11-30 03:04

    Your problem is that you're calling all the a s at once but you want to wait for the first cycle before going to the next. You want to wait for the previous 'a' cycle to finish before you start the next cycle.

    Let's assume a,b,c accept a callback, and pass it on,

    a would look like

    function a(param1, param2,callback) {
         $.post(..., function(result){
             if(result){
                b(callback);
             } else {
                console.log("failed a");
             }
         })
    }
    

    b would go like:

    function b(callback) {
          $.post(..., function(result){
             if(result){
                c(callback);
             } else {
                console.log("failed b");
             }
         })
    }
    

    And c would look like:

    function c(callback) {
         $.post(..., function(result){
             if(result){
                console.log("successful");
             } else {
                console.log("failed b");
             }
             callback();
         })
    }
    

    This lets us know when a cycle is complete. Which lets us write:

    var data = [{param1 : 1235, param2: 3214},  {param1 : 5432, param2: 9876}];
    
    var index = 0;
    (function updateData(){
        a(data[index].param1,data[index].param2,function(){ //call a with the data
            index++;//update the index 
            updateData(); // start the next cycle
        });
    });
    
    0 讨论(0)
  • 2020-11-30 03:10

    Here is an wonderfully simple and highly effect AJAX chaining / queue plugin. It will execute you ajax methods in sequence after each other.

    It works by accepting an array of methods and then executing them in sequence. It wont execute the next method whilst waiting for a response.

    //--- THIS PART IS YOUR CODE -----------------------

    $(document).ready(function () {

    var AjaxQ = [];
    AjaxQ[0] = function () { AjaxMethod1(); }
    AjaxQ[1] = function () { AjaxMethod2(); }
    AjaxQ[3] = function () { AjaxMethod3(); }
    
    //Execute methods in sequence
    $(document).sc_ExecuteAjaxQ({ fx: AjaxQ });
    

    });

    //--- THIS PART IS THE AJAX PLUGIN -------------------

    $.fn.sc_ExecuteAjaxQ = function (options) {

    //? Executes a series of AJAX methods in dequence
    
    var options = $.extend({
    
        fx: [] //function1 () { }, function2 () { }, function3 () { }
    
    }, options);
    
    if (options.fx.length > 0) {
    
        var i = 0;
    
        $(this).unbind('ajaxComplete');
        $(this).ajaxComplete(function () {
    
            i++;
            if (i < options.fx.length && (typeof options.fx[i] == "function")) { options.fx[i](); }
            else { $(this).unbind('ajaxComplete'); }
    
        });
    
        //Execute first item in queue
        if (typeof options.fx[i] == "function") { options.fx[i](); }
        else { $(this).unbind('ajaxComplete'); }
    
    } 
    

    }

    0 讨论(0)
  • 2020-11-30 03:11

    There are many ways to write this kind of thing.

    A flexible approach is separate "actions" from "sequence", allowing :

    • functions a, b, c to initiate an asynchronous (ajax) action, with no knowledge of how they are to be sequenced
    • a, b, c to be reusable, as part of one or more sequences or individually, as required.

    Here's a way to code this approach, using .then() exclusively for the chaining logic :

    function a() {
        return $.post(...).then(function(result) {
            if(result)
                return result;//continue on "success" path.
            else
                return $.Deferred().reject('a').promise();//convert success to failure.
        }, function() {
            return 'a';//continue on failure path.
        });
    }
    function b() {
        return $.post(...).then(function(result) {
            if(result)
                return result;//continue on "success" path.
            else
                return $.Deferred().reject('b').promise();//convert success to failure.
        }, function() {
            return 'b';//continue on failure path.
        });
    }
    function c() {
        return $.post(...).then(function(result) {
            if(result)
                return result;//continue on "success" path.
            else
                return $.Deferred().reject('c').promise();//convert success to failure.
        }, function() {
            return 'c';//continue on failure path.
        });
    }
    
    a().then(b).then(c).then(function() {
        console.log("successful");
    }, function(id) {
        console.log("failed: " + id);
    });
    

    Alternatively, if you want to have a single asynchronous function, a, called from within a loop then the code could be something like this :

    function a(obj) {
        return $.post(...).then(function(result) {
            if(result)
                return result;//continue on "success" path.
            else
                return $.Deferred().reject(obj.id).promise();//convert success to failure.
        }, function() {
            return obj.id;//continue on failure path.
        });
    }
    
    var data = [{id:'A', param1:1235, param2:3214},  {id:'B', param1:5432, param2:9876}];
    //Note how IDs are included so these data objects can be identified later in failure cases.
    
    var dfrd = $.Deferred();//starter Deferred for later resolution.
    var p = dfrd.promise();//A promise derived from the starter Deferred, forming the basis of a .then() chain.
    
    //Build a .then() chain by assignment
    $.each(data, function(i, obj) {
        p = p.then( function() {
            return a(obj);
        });//By not including a fail handler here, failures will pass straight through to be handled by the terminal .then()'s fail handler.
    });
    
    //Chain a terminal .then(), with success and fail handlers.
    p.then(function() {
        console.log("successful");
    }, function(id) {
        console.log("failed: " + id);
    });
    
    dfrd.resolve();//Resolve the starter Deferred to get things started.
    
    0 讨论(0)
  • 2020-11-30 03:17

    You can chain asynchronous calls like ajax calls using jQuery's deferred object and using 'then'.

    You can also change it to use functions that returns a deferred promise object, instead of an ajax call as I have in my example.

    http://jsfiddle.net/q4cFv/

    (Example with async function: http://jsfiddle.net/q4cFv/1/)

    $(function() {
        var delay = 3,
            span = $('span'),
            posts = [
                {
                    input1: 'My name 1',
                    input2: 'My address 1',
                    input3: 'My country 1'
                },
                {
                    input1: 'My name 2',
                    input2: 'My address 2',
                    input3: 'My country 2'
                },
                {
                    input1: 'My name 3',
                    input2: 'My address 3',
                    input3: 'My country 3'
                },
                {
                    input1: 'My name 4',
                    input2: 'My address 4',
                    input3: 'My country 4'
                }
            ],
            looper = $.Deferred().resolve();
    
        $.each(posts, function(i, data) {
            looper = looper.then(function() {
                return $.ajax({
                    data: {
                        json: JSON.stringify(data),
                        delay: delay
                    },
                    method: 'post',
                    url: '/echo/json/',
                    dataType: 'json'
                }).done(function(response) {
                    span.append('Response:<br />');
                    for(key in response) {
                        span.append(key + ': ' + response[key] + '<br />');
                    }
                    $('span').append('Waiting ' + delay + ' seconds<br /><br />');
                });
            });
        });
    });
    
    0 讨论(0)
  • 2020-11-30 03:21

    I see that c doesn't depend of b result, and b doesn't depend of a result.

    Following the GRASP principles (http://en.wikipedia.org/wiki/GRASP_(object-oriented_design), a mustn't know b and b mustn't know c.

    When we program, to remember the GRASP principles or guidelines is very important.

    High Cohesion and Low Coupling mean that our code will be better, more reusable and easier to maintain.

    The main function which knows a, b, and c must build the chained calls.

    The functions would be:

        function a(param1, param2) {
    
            var deferred = $.Deferred();
    
            console.log("    function a: begin. Params " + param1 + " and " + param2);
    
            mockPost("a_url").done(function() {
                console.log("    function a: end ok. Params " + param1 + " and " + param2);
                deferred.resolve();
            }).fail(function() {
                console.log("    function a: end fail. Params " + param1 + " and " + param2);
                deferred.reject();
            });
    
            return deferred.promise();
        }
    
        function b() {
    
            var deferred = $.Deferred();
    
            console.log("    function b: begin");
    
            mockPost("b_url").done(function() {
                console.log("    function b: end ok.");
                deferred.resolve();
            }).fail(function() {
                console.log("    function b: end fail.");
                deferred.reject();
            });
    
            return deferred.promise();
        }
    
        function c() {
    
            // We suppose that c function calls to post function and anything more
            return mockPost("c_url");
        }
    

    The main function would be:

        // Array with params for a function (a function is the first link in chain)
        var data = [{param1 : 1235, param2: 3214},  {param1 : 5432, param2: 9876}];
    
        // Array with calls to each fixed sequence a, b, and c. We iterate over data array
        var arrayFunctions = [];
        $.each(data, function(i,obj) {
            arrayFunctions.push(
                function() {
                    console.log("Params in data with index " + i + ":");
    
                    // We define the fixed sequence: a with params, b without params and c without params 
                    return $.iterativeWhen( 
                        function() {
                            return a(obj.param1, obj.param2);
                        },
                        b,
                        c
                    );
                }
            )
        });
    
        // Start the global process
        $.iterativeWhen.apply($, arrayFunctions)
        .done(function() {
            console.log ("----------------");
            console.log ("> Global Success");       
        })
        .fail(function() {
            console.log ("--------------");
            console.log ("> Global Fail");
        });
    

    $.iterativeWhen doesn't exist in jQuery, so I have built it. It works with jQuery 1.8 and later versions.

    $.iterativeWhen = function () {
    
        var deferred = $.Deferred();
        var promise = deferred.promise();
    
        $.each(arguments, function(i, obj) {
    
            promise = promise.then(function() {
                return obj();
            });
        });
    
        deferred.resolve();
    
        return promise;
    };
    

    The mockPost function simulates a call to $.post with a success probability:

    function mockPost(url) {
    
            var deferred = $.Deferred();
    
            setTimeout(function() {
                if (Math.random() <= 0.9) {
                    console.log("        request url: " + url +  "... ok");
                    deferred.resolve();
                } else {
                    console.log("        request url: " + url +  "... fail");
                    deferred.reject();
                }
            }, 1000);
    
            return deferred.promise();
        }
    

    The log output is:

    Params in data with index 0: 
        function a: begin. Params 1235 and 3214 
            request url: a_url... ok 
        function a: end ok. Params 1235 and 3214 
        function b: begin 
            request url: b_url... ok 
        function b: end ok. 
            request url: c_url... ok 
    Params in data with index 1: 
        function a: begin. Params 5432 and 9876
            request url: a_url... ok
        function a: end ok. Params 5432 and 9876 
        function b: begin 
            request url: b_url... ok 
        function b: end ok. 
            request url: c_url... ok 
    ---------------- 
    > Global Success 
    

    jsFiddle here: http://jsfiddle.net/E2tp3/

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