So überprüfen Sie, ob ein Angular $ q-Versprechen gelöst ist

84

Ich verstehe, dass man normalerweise nur Fortsetzungscode mit einem then()Anruf- und Kettenverhalten anfügt, wenn man Versprechen verwendet.

Ich möchte jedoch einen asynchronen Anruf mit $timeout()Versprechen abschließen und dann separat eine 3-Sekunden- Aktion starten, damit ich eine UI-Aktion ausführen kann, NUR WENN das ursprüngliche Versprechen noch nicht abgeschlossen ist. (Ich gehe davon aus, dass dies nur bei langsamen Verbindungen, mobilen Geräten mit 3G usw. passieren wird.)

Kann ich bei einem versprochenen Versprechen überprüfen, ob es vollständig ist oder nicht, ohne zu blockieren oder zu warten?

Blaster
quelle
2
Ich habe ein Problem zu diesem Thema in
Angular
Mögliches Duplikat von stackoverflow.com/questions/27039771/…
mvermand

Antworten:

46

Ich denke, dies wurde in einer neueren Version von Angular hinzugefügt, aber es scheint jetzt ein $$ -Statusobjekt auf dem Versprechen zu geben:

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

Wie in den Kommentaren erwähnt, wird dies nicht empfohlen, da es beim Upgrade Ihrer Angular-Version zu Problemen kommen kann.

Parlament
quelle
25
Angular Docs sagen, dass $$...Eigenschaften nicht verwendet werden sollten.
Könnte
7
Schade, dass Angular seine privaten Variablen auf einem Silbertablett bereitstellt. :(
Jackson
2
Aber aber ... Angular hat die inspectFunktion nicht implementiert . Also kein Saft für uns Angular Entwickler. Promise Prototyp hat es einfach nicht.
Robert Koritnik
36

Ich denke, Ihre beste Option (ohne die Angular-Quelle zu ändern und eine Pull-Anfrage zu senden) ist es, ein lokales Flag zu behalten, wenn das Versprechen gelöst wurde. Setzen Sie es jedes Mal zurück, wenn Sie das Versprechen einrichten, an dem Sie interessiert sind, und markieren Sie es als vollständig then()für das ursprüngliche Versprechen. Aktivieren Sie das $timeout then()Kontrollkästchen, um festzustellen, ob das ursprüngliche Versprechen noch gelöst wurde oder nicht.

Etwas wie das:

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

Die Implementierung von Kris Kowal beinhaltet andere Methoden zur Überprüfung des Versprechensstatus, aber es scheint, dass Angulars Implementierung diese $qleider nicht enthält.

Shaunhusain
quelle
9
Es wäre besser, hier .finally () zu verwenden. Der oben angegebene Code markiert das Versprechen-abgeschlossen-Flag nur dann als wahr, wenn es erfolgreich aufgelöst wurde.
Karanvir Kang
8

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

// 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);
Bergi
quelle
1

Ich hatte ein ähnliches Problem, bei dem ich überprüfen muss, ob ein Versprechen zurückgekehrt ist. Da die $watchFunktion von AngularJS beim Rendern der Seite eine Änderung registriert, auch wenn sowohl neue als auch alte Werte nicht definiert sind, muss ich überprüfen, ob Daten in meinem externen Modell gespeichert werden sollten.

Es ist definitiv ein Hack, aber ich mache das:

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

Ich weiß, dass dies $$veine interne Variable ist, die von AngularJS verwendet wird, aber sie war ziemlich zuverlässig als Indikator für ein gelöstes Versprechen für uns. Wer weiß, was passieren wird, wenn wir auf AngularJS 1.2 aktualisieren: - / Ich sehe keine Erwähnung von Verbesserungen $qin den 1.2-Dokumenten, aber vielleicht schreibt jemand einen Ersatzdienst mit einem besseren Funktionsumfang näher an Q.

PatchCR
quelle
Danke, aber es gibt bessere Möglichkeiten als "private" Mitglieder.
Jackson
0

Ich kenne Ihr genaues Szenario nicht, aber es ist typischer, unmittelbar nach dem asynchronen Anruf (und dem Generieren des Versprechens) eine Zeitüberschreitung einzurichten.

Vorausgesetzt, die setTimeout()Anweisung befindet sich im selben Ereignisthread wie der asynchrone Aufruf, müssen Sie sich keine Gedanken über die Möglichkeit eines Race-Effekts machen. Da Javascript ausschließlich aus einem Thread besteht, werden die .then()Rückrufe des Versprechens garantiert in einem späteren Ereignisthread ausgelöst.

Rote Beete-Rote Beete
quelle