2016-03-08 3 views
11

Ich versuche zu verstehen, die Versprechen API und Verkettung, insbesondere das Timing, wenn $timeout mit verwendet wird. Was ich von dem folgenden erwartet hatte, ist, dass $timeout ein Versprechen zurückgibt, würde nicht aufgerufen werden, bis es aufgelöst wurde.

Aber statt ABAB ist es ABBA die ganze Zeit.

Wie kann ich mithilfe der Promise-API sicherstellen, dass ein lang andauernder Anruf (oder ein verzögerter Anruf unter Verwendung von $timeout) tatsächlich abgeschlossen ist, bevor die ausgeführt wird?

-Code

angular 
    .module('app', []) 
    .controller('ThenCtrl', ThenCtrl); 

function ThenCtrl($timeout, $q) { 
    var vm = this; 

    vm.items = []; 

    $q.when(pushA()).then(pushB()); 

    $timeout(pushA, 5000).then(pushB()); 

    function pushA() { 
    vm.items.push('A'); 
    } 

    function pushB() { 
    vm.items.push('B'); 
    } 
} 

Markup

<div ng-app="app"> 
    <div ng-controller="ThenCtrl as vm"> 
    {{vm.items}} 
    </div> 
</div> 

ich eine Geige eingerichtet haben: https://jsfiddle.net/kan3c61t/

Antwort

13

Sie die Funktionen innerhalb der .then Methoden nicht aufrufen.

$q.when(pushA()).then(pushB); 
    //$q.when(pushA()).then(pushB()); 

    $timeout(pushA, 5000).then(pushB); 
    //$timeout(pushA, 5000).then(pushB()); 

Stattdessen übergeben Sie die Funktionen als Argumente an die .then Methode. Der Dienst $q enthält diese Funktionen, die später aufgerufen werden.

Die Art und Weise, wie der $q-Dienst funktioniert, speichert das Argument der .then-Methode als Funktion, die später aufgerufen wird. In diesem Fall speichert der Dienst $q den von pushB() zurückgegebenen Wert mit dem Nebeneffekt, dass sofort B auf das Array geschoben wird.

Die DEMO on JSFiddle

+0

Dies ist auch eine ziemlich interessante Lösung. –

+2

Sehr deutlich angegeben. Was für ein Unterschied diese Klammernpaare machen können. – twip

+0

Das hat mir enorm geholfen – Fergus

6

Hier gehen Sie. Was ich getan habe, ist im Wesentlichen eine success Funktion im then Teil des Codes hinzugefügt.

$timeout(pushA, 5000).then(function(success) { 
    pushB() 
    }); 

Hier ist die Arbeit demo.

Sie können auch eine error function wie diese

$timeout(pushA, 5000).then(function(success) { 
    pushB() 
    },function(error){console.log("Error");}); 

hinzufügen Während für diese Antwort suchen, kam ich auch über diese sehr helpful link

+1

Dies ist eine hervorragende Erinnerung an die zugrunde liegende API-Struktur; Danke. – twip

4

Wie andere erwähnt haben - Ihr größeres Problem ist, dass Sie .then(promise) und nicht .then(function).

Versprechen stellen einen Wert + Zeit dar. Es ist das Ergebnis eines bereits gestarteten Vorgangs. Ein Versprechen ist ein Wert - then wartet auf Funktionen. Sie können kein Versprechen nach einem anderen Versprechen ablegen - da ein Versprechen bedeutet, dass die Operation bereits begonnen hat.

Wenn Sie then(x) für etwas anderes als eine Funktion wird ignoriert.Dies ist eine unglückliche Wahl in den Versprechen Spezifikationen, aber wir müssen damit leben.

Da Ihre Anrufe synchron sind, sollten Sie keine Versprechungen dafür verwenden. Wenn Ihr Code tut synchron etwas, das Sie Aktionen mit ; sequenzieren können und nicht then:

pushA(); 
pushB(); 

Wenn es ein Anruf ist, dass es wieder verspricht, dann wird gerade:

pushA().then(pushB); 

Es gibt keinen Punkt $q.when in Berufung, die wandelt Nichtversprechen in Versprechen um.

Ich würde schreiben Sie es als:

pushA(); 
$timeout(5000).then(pushB); 

Es gibt keinen Grund, die erste Synchronaktion zu einem Versprechen der Rückkehr Funktion oder einzubinden Versprechen überall mit Ausnahme des Timeout zu konvertieren. Wenn Sie pushA müssen nach 5000ms passieren selbst würde ich wahrscheinlich immer noch schreiben:

$timeout(5000).then(pushA).then(pushB) 

Da ich denke, es ist besser lesbar und wieder tun beziehen wir nicht pushA und pushB mit Versprechungen direkt.

+0

Vielen Dank für die Antwort. Es ist manchmal sehr schwierig, die Absicht gut zu erfassen, während es für SO-Posts gleichzeitig kurz und klar ist. Was ich zu erfassen versuchte, ist ein Szenario, in dem wir beabsichtigen, A vor B zu lösen, und A ist das Versprechen, das die Verzögerung tragen muss. Bedeutung: Ich möchte 'pushA', um seine Arbeit abzuschließen, einschließlich der Verzögerung, und dann-und-nur-dann 'pushB' ausführen. Hier ist eine aktualisierte Geige, die mit Ihren Eingaben umgesetzt wurde und mir dabei half, das zu erreichen, wonach ich gesucht hatte: https://jsfiddle.net/nam3cbaw/1/ – twip