jQuery 链接ajax并按顺序执行。Jquery延迟

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16384841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 17:02:55  来源:igfitidea点击:

Chain ajax and execute it in sequence. Jquery Deferred

javascriptjqueryajaxeachdeferred

提问by Joey Hipolito

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

我有 3 个需要 ajax 才能完成的进程。但它是异步的,它没有做我想做的事。

Lets say:

让我们说:

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

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

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

I want it to execute like this

我希望它像这样执行

a
b
c

That code will work perfectly, as you can see.. but if use a loop.

如您所见,该代码将完美运行......但如果使用循环。

 var data = [{param1 : 1235, param2: 3214},  {param1 : 5432, param2: 9876}];

 $.each(data, function(k,v){
      a(v.param1, v.param2)
 });

It will not work as expected and will just do:

它不会按预期工作,只会做:

a
a
b
b
c
c

instead of

代替

a
b
c
a
b
c

回答by Beetroot-Beetroot

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.
  • 函数 a, b, c 启动异步 (ajax) 操作,不知道它们将如何排序
  • a、b、c 可重复使用,作为一个或多个序列的一部分或根据需要单独使用。

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

这是一种编写此方法的方法,.then()专门用于链接逻辑:

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 :

或者,如果您想a在循环内调用单个异步函数,则代码可能如下所示:

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.

回答by thebreiflabb

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

您可以使用 jQuery 的延迟对象并使用“then”来链接异步调用,例如 ajax 调用。

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.

您还可以将其更改为使用返回延迟承诺对象的函数,而不是我在示例中使用的 ajax 调用。

http://jsfiddle.net/q4cFv/

http://jsfiddle.net/q4cFv/

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

(异步功能示例: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 />');
            });
        });
    });
});

回答by Alejandro Cobo Cobo

I see that cdoesn't depend of bresult, and bdoesn't depend of aresult.

我看到Ç不依赖的b结果,而b不依赖的一个结果。

Following the GRASP principles (http://en.wikipedia.org/wiki/GRASP_(object-oriented_design), amustn't know band bmustn't know c.

遵循 GRASP 原则 ( http://en.wikipedia.org/wiki/GRASP_(object-oriented_design)a不能知道bb不能知道c

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

当我们编程时,记住 GRASP 原则或指南非常重要。

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 cmust build the chained calls.

知道abc的 main 函数必须构建链式调用。

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 在 jQuery 中不存在,所以我构建了它。它适用于 jQuery 1.8 及更高版本。

$.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:

mockPost 函数以成功概率模拟对 $.post 的调用:

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/

jsFiddle在这里:http: //jsfiddle.net/E2tp3/

回答by MarzSocks

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

这是一个非常简单且高效的 AJAX 链接/队列插件。它会依次执行你的ajax方法。

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

} 

}

//--- 这部分是你的代码 ---------------

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

});

//--- 这部分是 AJAX 插件 -------------------

$.fn.sc_ExecuteAjaxQ = 函数(选项){

//? 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'); }

} 

}

回答by Benjamin Gruenbaum

Your problem is that you're calling all the as 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.

你的问题是你a一次调用所有的s 但你想在进入下一个循环之前等待第一个循环。您希望在开始下一个周期之前等待前一个“a”周期完成。

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

让我们假设 a,b,c 接受一个回调,并传递它,

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:

b 会这样:

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

And c would look like:

而 c 看起来像:

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