2012-11-30 8 views
16

Da diese Funktionen:Wie verkette ich eine Sequenz von zurückgestellten Funktionen in jQuery 1.8.x?

function func1() { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    dfd.resolve('Password'); 
    }, 1000); 

    return dfd.promise(); 
} 

function func2(message) { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    if (message == 'Password') { 
     dfd.resolve('Hello World'); 
    } 
    }, 1000); 

    return dfd.promise(); 
} 

würde Ich mag einen besseren Weg finden, die folgenden zu tun. Beachten Sie, dass dies jQuery 1.8.x verwendet.

var promise = func1(); 

promise.done(function(message1) { 

    var promise2 = func2(message1); 

    promise2.done(function(message2) { 
    alert(message2); 
    }); 
}); 

Irgendwelche Ideen? Ich dachte, mit jQuery #pipe oder # würde dann funktionieren, aber ich kann es nicht herausfinden. Hier ist eine Geige zum Spielen: http://jsfiddle.net/Z7prn/

Antwort

34

Es ist nicht so kompliziert (entweder .then oder .pipe verwenden, sie sind beide gleich seit jQuery 1.8 ich denke).

promise.then(func2).done(function(message) { 
    alert(message); 
}); 

Seit func2 gibt ein neues latentes Objekt, der .done Rückruf stattdessen zu, dass man verbunden ist.

DEMO

+1

ich liebe, wenn die Menschen die Dinge in so prägnanter Form zu erklären. einfacher zu verstehen und zu folgen – tim

+1

Hinweis: Verwenden Sie ". Then", da '.pipe' in jQuery 1.8 veraltet ist ([docs] (http://api.jquery.com/deferfer.pipe/)) – nhylated

-2

Verwendung JQuery.when(). Es ist genau das, was Sie ein Array von verzögerten verknüpfen möchten und eine Funktion ausführen, wenn alle fertig sind.

-Update 2017 (nach downvotes sehen):

Was OP wollte, war eine bessere Version seines Code Versprechen der Reihe nach ausgeführt werden. Hier ist meine Version mit $.when:

function func1() { 
 
    var dfd = $.Deferred(); 
 

 
    setTimeout(function() { 
 
    dfd.resolve('Password'); 
 
    }, 1000); 
 

 
    return dfd.promise(); 
 
} 
 

 
function func2(message) { 
 
    var dfd = $.Deferred(); 
 

 
    setTimeout(function() { 
 
    if (message == 'Password') { 
 
     dfd.resolve('Hello World'); 
 
    } 
 
    }, 1000); 
 

 
    return dfd.promise(); 
 
} 
 

 
// ~~~~~~~~~~ using $.when here ~~~~~~~~~~~~ 
 

 
$.when(func1()).then(function(result1) { 
 
    $.when(func2(result1)).then(function(result2) { 
 
     alert(result2); 
 
    }) 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>

+5

Sie sind nicht angekettet - sie werden gesammelt. Das Array von Defers wird "sofort" abgefeuert, und das When() - Callback wird mit allen ausgeführt. then(), auf der anderen Seite, kann so verkettet werden, dass func1() vor func2() etc. aufgelöst werden muss. –

+0

@DesignbyAdrian Warum interpretieren Sie die Frage von OP anders ?! Sie können seinen geposteten Code ausführen oder den Titel lesen und sehen, dass er * will * sie _ketten_. Er ist nur auf der Suche nach einer Möglichkeit, die zweite Snipped auf eine bessere Weise umzuschreiben und das ist, was ich erwähnt habe und nur ein Beispiel hinzugefügt. Die Ausgabe meines Snippets ist dieselbe wie seine (wie er wollte) in 3 LOC. – Aidin

5

Ich hatte einen ähnlichen Anwendungsfall, also denke ich, dies sollten Ihnen helfen.

Die folgende Methode benötigt ein Array von Methoden (die Promises zurückgeben können oder nicht) und sie nacheinander ausführen, wobei gewartet wird, bis jede Deferred abgeschlossen ist, bevor Sie fortfahren. Das Standardverhalten besteht darin, bei einem Fehler zu stoppen. Mit dem zweiten Argument können Sie fortfahren, ob der Anruf fehlschlägt oder nicht.

getan/Handler Signaturen (Array < Kontext>) Funktion (Array < Objekt {abgelehnt | aufgelöst: Argumente}>) fehlschlagen, wo Kontext ist der Kontext jedes resolveWith/rejectWith Anruf oder das in Frage stehende Deferred, und Argumente ist das Argument, das in der Auflösung/Zurückweisung übergeben wurde.

(function ($) { 
    "use strict"; 
    var copy = function (a) { 
     return Array.prototype.slice.call(a); 
    }; 

    /** 
     Handle a sequence of methods, stopping on failure by default 
     @param Array<Function> chain List of methods to execute. Non-deferred return values will be treated as successful deferreds. 
     @param Boolean continueOnFailure Continue executing even if one of the returned deferreds fails. 
     @returns Deferred 
    */ 
    $.sequence = function (chain, continueOnFailure) { 
     var handleStep, handleResult, 
      steps = copy(chain), 
      def = new $.Deferred(), 
      defs = [], 
      results = []; 
     handleStep = function() { 
      if (!steps.length) { 
       def.resolveWith(defs, [ results ]); 
       return; 
      } 
      var step = steps.shift(), 
       result = step(); 
      handleResult(
       $.when(result).always(function() { 
        defs.push(this); 
       }).done(function() { 
        results.push({ resolved: copy(arguments) }); 
       }).fail(function() { 
        results.push({ rejected: copy(arguments) }); 
       }) 
      ); 
     }; 
     handleResult = continueOnFailure ? 
       function (result) { 
        result.always(function() { 
         handleStep(); 
        }); 
       } : 
       function (result) { 
        result.done(handleStep) 
         .fail(function() { 
          def.rejectWith(defs, [ results ]); 
         }); 
       }; 
     handleStep(); 
     return def.promise(); 
    }; 
}(this.jQuery)); 

Ein einfaches Beispiel für die Verwendung: http://jsfiddle.net/rG9rA/

function func1() { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    dfd.resolve('Password'); 
    }, 1000); 

    return dfd.promise(); 
} 

function func2(message) { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    if (message == 'Password') { 
     dfd.resolve('Hello World'); 
    } 
    }, 1000); 

    return dfd.promise(); 
} 

    $.sequence([func1, func2, function() { alert('done'); }]); 
+0

Schön. Ich habe eine optionale "Verzögerung" zwischen den Anrufen hinzugefügt, falls ein externer Code Ereignisse benötigt, die erledigt werden müssen (ich benutze Knockout) –