2013-07-26 18 views
78

Ich verstehe, dass man normalerweise Fortsetzungscode mit einem then() Call-and-Chain-Verhalten bei der Verwendung von Versprechen anfügen würde.

Allerdings möchte ich einen Versprechen asynchronen Anruf starten und dann separat starten 3-Sekunden-$timeout(), damit ich eine UI-Aktion nehmen kann, nur wenn das ursprüngliche Versprechen noch nicht abgeschlossen ist. (Ich nehme an, dass dies nur auf langsamen Verbindungen, mobilen Geräten auf 3G, etc. passieren würde)

Angesichts einer Zusage, kann ich überprüfen, ob es abgeschlossen ist oder nicht, ohne zu blockieren oder zu warten?

+2

Ich öffnete ein Problem in diesem Winkel und erhielt eine hilfreiche Antwort https://github.com/angular/angular.js/issues/8307#issuecomment-49903373 – derekdreery

+0

mögliche Duplikat von http://stackoverflow.com/questions/27039771/q-js-ist-es-möglich-zu-wissen-wenn-ein-Versprechen-hat-gelöst-abgelehnt-oder-nicht – mvermand

Antwort

36

Ich denke, Ihre beste Option ist, (ohne die Angular-Quelle zu modifizieren und eine Pull-Anfrage zu übermitteln), eine lokale Flagge zu behalten, wenn das Versprechen gelöst wurde. Setzen Sie es jedes Mal zurück, wenn Sie das Versprechen eingerichtet haben, das Sie interessiert, und markieren Sie es als vollständig in der then() für das ursprüngliche Versprechen. In der $timeoutthen() überprüfen Sie die Flagge zu wissen, ob das ursprüngliche Versprechen noch nicht gelöst hat oder nicht.

Etwas wie folgt aus:

var promiseCompleted = false; 
promise.then(function(){promiseCompleted=true;}) 
$timeout(...).then(function(){if(!promiseCompleted)doStuff()}) 

Kris Kowal Implementierung schließt andere Methoden, um den Zustand des Versprechens Kontrolle, aber es scheint Angular Implementierung von $q leider nicht diese enthält.

+7

Es wäre besser, .finally() hier zu verwenden. Der oben bereitgestellte Code markiert das "promiseCompleted" -Flag nur dann als "true", wenn es erfolgreich aufgelöst wurde. –

+0

Guter Punkt, schließlich ist wahrscheinlich besser – shaunhusain

0

Ich kenne Ihr genaues Szenario nicht, aber es ist typischer, eine Zeitüberschreitung direkt nach dem asynchronen Aufruf zu setzen (und das Versprechen zu generieren).

Wenn die Anweisung setTimeout() im selben Ereignis-Thread wie der asynchrone Aufruf bereitgestellt wird, müssen Sie sich keine Gedanken über die Möglichkeit eines Race-Effekts machen. Da JavaScript strikt single-threaded ist, werden die Callbacks des Versprechens garantiert in einem späteren Ereignis-Thread ausgelöst.

+0

Dann bricht der Code, wenn Browser asynchrone JavaScript wie 'node' implementieren. –

8

Es scheint nicht möglich zu sein, wie @shaunhusain bereits erwähnt. Aber vielleicht ist es nicht notwendig:

// shows stuff from 3s ahead to promise completetion, 
// or does and undoes it in one step if promise completes before 
$q.all(promise, $timeout(doStuff, 3000)).then(undoStuff); 

oder vielleicht besser:

var tooSlow = $timeout(doStuff, 3000); 
promise.always(tooSlow.cancel); 
1

Ich habe ein ähnliches Problem hat, wo ich zu überprüfen, ob ein Versprechen zurückgekehrt ist. Da die Funktion $watch von AngularJS eine Änderung beim Rendern der Seite registriert, auch wenn sowohl der neue als auch der alte Wert nicht definiert sind, muss ich überprüfen, ob Daten in meinem externen Modell gespeichert werden können.

Es ist auf jeden Fall ein Hack, aber ich dies tun:

$scope.$watch('userSelection', function() { 
    if(promiseObject.hasOwnProperty("$$v"){ 
    userExportableState.selection = $scope.userSelection; 
    } 
}; 

Ich weiß, dass $$v eine interne Variable von AngularJS verwendet, aber es hat sich als Indikator eines aufgelösten Versprechen für uns recht zuverlässig. Wer weiß, was passieren wird, wenn wir auf AngularJS 1.2 upgraden: -/Ich sehe keine Erwähnung von Verbesserungen an $q in der 1.2 Dokumentation, aber vielleicht wird jemand einen Ersatzdienst mit einem besseren Feature-Set näher an Q schreiben.

+0

Danke, aber es gibt bessere Möglichkeiten als die Verwendung von "privaten" Mitgliedern. – Jackson

45

Ich denke, dies wurde in einer aktuellen Version von Angular hinzugefügt, aber es scheint jetzt auf dem Versprechen ein $$ Zustand Objekt zu sein:

var deferred = $q.defer(); 
console.log(deferred.promise.$$state.status); // 0 
deferred.resolve(); 
console.log(deferred.promise.$$state.status); //1 

Wie in den Kommentaren darauf hingewiesen, das nicht, wie es empfohlen wird, könnte brechen wenn Sie Ihre Angular-Version aktualisieren.

+23

Angular Docs sagen '' $$ ... 'Eigenschaften sollten nicht verwendet werden. Könnte riskant sein, wenn Sie auf neuere Versionen von Angular aktualisieren ... – hgoebl

+7

Schade Angular stellt seine privaten Variablen auf einem Silbertablett zur Verfügung. :( – Jackson

+2

siehe auch: http://stackoverflow.com/questions/27039771/q-js-is-it-possible-to-know-if-a-promise-has-resolved-rejected-or-not – mvermand

Verwandte Themen