15

完了するために ajax が必要な 3 つのプロセスがあります。しかし、それは非同期であり、私がやりたかったことを行うことができません..

まあ言ってみれば:

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

このように実行したい

a
b
c

ご覧のとおり、そのコードは完全に機能します..しかし、ループを使用する場合.

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

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

期待どおりに機能せず、次のようになります。

a
a
b
b
c
c

それ以外の

a
b
c
a
b
c
4

5 に答える 5

17

このような書き方はいろいろあります。

柔軟なアプローチは、「アクション」を「シーケンス」から分離することで、次のことが可能になります。

  • 関数 a、b、c は非同期 (ajax) アクションを開始しますが、それらがどのように順序付けられるかはわかりません
  • a、b、c は、必要に応じて、1 つまたは複数のシーケンスの一部として、または個別に再利用できます。

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

または、ループ内から呼び出される単一の非同期関数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.
于 2013-05-05T18:39:57.120 に答える
6

jQuery の遅延オブジェクトと「then」を使用して、ajax 呼び出しのような非同期呼び出しを連鎖させることができます。

私の例のように ajax 呼び出しの代わりに、延期された promise オブジェクトを返す関数を使用するように変更することもできます。

http://jsfiddle.net/q4cFv/

(非同期関数の例: 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 />');
            });
        });
    });
});
于 2013-05-05T13:37:30.830 に答える
3

あなたの問題は、a一度にすべての s を呼び出しているが、次のサイクルに進む前に最初のサイクルを待ちたいということです。次のサイクルを開始する前に、前の「a」サイクルが終了するのを待ちたいとします。

a,b,c がコールバックを受け入れ、それを渡すとしましょう。

のようになります

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

b は次のようになります。

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

c は次のようになります。

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

これにより、サイクルがいつ完了したかがわかります。これにより、次のように記述できます。

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
    });
});
于 2013-05-05T13:27:09.523 に答える
3

これは、驚くほどシンプルで非常に効果的な AJAX チェーン / キュー プラグインです。ajax メソッドを順番に実行します。

メソッドの配列を受け取り、それらを順番に実行することで機能します。応答を待っている間、次のメソッドを実行しません。

//--- この部分はあなたのコードです -----------------------

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

} 

}

于 2013-10-30T11:25:35.737 に答える