2013-05-05 7 views
12

Ich habe 3 Prozesse, die Ajax benötigt, um abzuschließen. Aber es asynchron ist und es nicht zu tun, was ich tun wollte ..Verketten Sie Ajax und führen Sie es nacheinander aus. Jquery Defered

Lassen Sie uns sagen:

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

ich es wie dieses

a 
b 
c 

Dieser Code perfekt funktioniert ausführen möchten, wie Sie sehen können .. aber wenn eine Schleife verwenden.

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

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

Es wird nicht wie erwartet funktionieren und wird nur tun:

a 
a 
b 
b 
c 
c 

statt

a 
b 
c 
a 
b 
c 
+0

nichts ist falsch mit ur Struktur .. u kann genauen abt des Code geben .. – Sarath

+0

ja, es ist nichts falsch mit ihm, aber wenn Sie lesen die Ausführung entlang, Code, wenn Schleife ist aa, bb, cc anstelle von abc, a bc –

+0

also hw ur bleib dran was zuerst heißt .. jetzt stellst du konsole nur auf fail .. – Sarath

Antwort

3

Ihr Problem ist, dass Sie alle a s auf einmal bist rufen, aber sie Ich möchte auf den ersten Zyklus warten, bevor ich zum nächsten gehe. Sie möchten auf den vorherigen Zyklus 'a' warten, bevor Sie den nächsten Zyklus starten.

wir a, b annehmen, c einen Rückruf annehmen, und übergeben es an,

ein wie

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

b gehen würde wie folgt aussehen würde: würde

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

Und c aussehen wie:

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

Diese le Wir wissen, wann ein Zyklus abgeschlossen ist. Welche können wir schreiben:

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

Ich werde das ausprobieren .. –

+0

Dies wird Fehler am Ende zurückgegeben, sagen undefined Eigenschaft von param1 ... –

+0

Dies ist __Sample Code__ es ist für _learning_ gedacht. Zum Beispiel müssen Sie überprüfen, ob Sie das Array beendet haben und keine Rekursion dann –

5

Sie können Kette asynchrone Aufrufe wie Ajax-Aufrufe jQuery latenten Objekt verwenden und mit ‚dann‘.

Sie können es auch ändern, um Funktionen zu verwenden, die anstelle eines Ajax-Aufrufs ein verzögertes Zusicherungsobjekt zurückgibt, wie ich in meinem Beispiel habe.

http://jsfiddle.net/q4cFv/

(Beispiel mit Asynchron-Funktion: 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 />'); 
      }); 
     }); 
    }); 
}); 
+1

Ich denke, das ist, was ich suche ... zurückgestellt. –

14

Es gibt viele Möglichkeiten, diese Art der Sache zu schreiben.

Ein flexiblerer Ansatz ist getrennt „Aktionen“ von „Sequenz“, so dass:

  • Funktionen a, b, c einem asynchronen (Ajax) Aktion, ohne Kenntnis der zu initiieren, wie sie sind zu sequenzierenden
  • a, b, c wiederverwendbar, als Teil einer oder mehrerer Sequenzen oder einzeln, je nach Bedarf.

Hier ist ein Weg, um diesen Ansatz zu codieren, .then() ausschließlich für die Verkettungslogik:

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

Alternativ, wenn Sie eine einzelne asynchrone Funktion haben wollen, a, innerhalb einer Schleife dann die Code könnte so etwas wie dieses:

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

danke für das verzögerte Beispiel, genau das, was ich suchte !! –

+0

also, wenn das in einer Funktion wäre, würden Sie 'dfrd' zurückgeben, damit der Anrufer es auflösen kann? oder würdest du es hier auflösen und das Versprechen zurückgeben, damit der Aufrufer .then() s daran anhängen kann? – ekkis

4

ich sehe, dass c nicht von abhängt b Ergebnis, und b hängt nicht von ein Ergebnis ab.

den GRASP Prinzipien verfolgt (http://en.wikipedia.org/wiki/GRASP_(object-oriented_design), ein muss wissen nicht b und b nicht c wissen müssen.

Wenn wir programmieren, um die GRASP Grundsätze oder Richtlinien zu erinnern sehr wichtig.

High Cohesion und Low Kopplung bedeuten, dass unser Code besser sein wird, mehr wiederverwendbar und leichter zu pflegen.

Die Hauptfunktion, die a, b und c kennt, muss die verketteten Aufrufe erstellen.

würden die Funktionen sein:

// 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 existiert nicht in jQuery, so habe ich es gebaut:

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

Die Hauptfunktion sein würde. Es funktioniert mit jQuery 1.8 und späteren Versionen.

$.iterativeWhen = function() { 

    var deferred = $.Deferred(); 
    var promise = deferred.promise(); 

    $.each(arguments, function(i, obj) { 

     promise = promise.then(function() { 
      return obj(); 
     }); 
    }); 

    deferred.resolve(); 

    return promise; 
}; 

Die mockPost Funktion simuliert einen Aufruf $ .post mit einer Erfolgswahrscheinlichkeit:

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

Die Protokollausgabe ist:

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 hier: http://jsfiddle.net/E2tp3/

2

Hier ist ein wunderbar einfaches und sehr effektives AJAX Chaining/Queue Plugin. Es führt Sie Ajax-Methoden hintereinander nacheinander aus.

Es funktioniert, indem ein Array von Methoden akzeptiert und dann in Folge ausgeführt wird. Es wird nicht die nächste Methode ausführen, während auf eine Antwort gewartet wird.

// --- DIESER ARTIKEL IST IHR CODE -----------------------

$ (Dokument).bereit (Funktion()) {

var AjaxQ = []; 
AjaxQ[0] = function() { AjaxMethod1(); } 
AjaxQ[1] = function() { AjaxMethod2(); } 
AjaxQ[3] = function() { AjaxMethod3(); } 

//Execute methods in sequence 
$(document).sc_ExecuteAjaxQ({ fx: AjaxQ }); 

});

// --- Dieser Teil ist der AJAX PLUGIN -------------------

$ .fn.sc_ExecuteAjaxQ = function (Optionen) {

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

} 

}