wake-up-neo.com

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

Ich verstehe, dass man normalerweise nur einen Fortsetzungscode mit einem then() Aufruf- und Kettenverhalten anfügt, wenn Versprechungen verwendet werden.

Ich möchte jedoch einen versprechensumhüllten asynchronen Anruf starten und dann separat einen 3-Sekunden-Befehl $timeout() starten, damit ich eine Benutzeroberflächenaktion ausführen kann, NUR WENN das ursprüngliche Versprechen noch nicht abgeschlossen ist. (Ich gehe davon aus, dass dies nur bei langsamen Verbindungen, Mobilgeräten mit 3G usw. der Fall sein wird.)

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

83
blaster

Ich denke, dies wurde in einer neueren Version von Angular hinzugefügt, aber es scheint nun ein $$ state-Objekt zu geben, das das Versprechen enthält:

 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.

46
parliament

Ich denke, Ihre beste Option ist es (ohne Änderung der Angular Quelle und Einreichen einer Pull-Anfrage), ein lokales Flag für den Fall zu behalten, dass das Versprechen gelöst wurde. Setzen Sie es jedes Mal zurück, wenn Sie das einrichten Versprechen, an dem Sie interessiert sind, und markieren Sie es als vollständig in der then() für das ursprüngliche Versprechen. Aktivieren Sie im $timeoutthen() das Kontrollkästchen, um festzustellen, ob das ursprüngliche Versprechen erfüllt ist gelöst noch oder nicht.

Etwas wie das:

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

Die Implementierung von Kris Kowal enthält andere Methoden zur Überprüfung des Versprechenstatus, aber es scheint, dass Angulars Implementierung von $q Diese leider nicht enthält.

36
shaunhusain

Es scheint nicht möglich zu sein, wie @shaunhusain bereits erwähnte. 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);
8
Bergi

Ich hatte ein ähnliches Problem, bei dem ich überprüfen muss, ob ein Versprechen zurückgegeben wurde. Weil AngularJS's $watch-Funktion registriert eine Änderung beim Rendern der Seite, auch wenn neue und alte Werte nicht definiert sind. Ich muss überprüfen, ob in meinem externen Modell Daten 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ß das $$v ist eine interne Variable, die von AngularJS verwendet wird, aber als Indikator für ein gelöstes Versprechen für uns ziemlich zuverlässig war. Wer weiß, was passiert, wenn wir auf AngularJS 1.2 upgraden: -/Ich sehe keine Erwähnung von Verbesserungen an $q in den 1.2-Dokumenten, aber vielleicht schreibt jemand einen Ersatzdienst mit einem besseren Funktionsumfang, der näher an Q ist.

1
PatchCR

Ich kenne Ihr genaues Szenario nicht, aber es ist üblicher, ein Timeout unmittelbar nach dem asynchronen Anruf (und dem Generieren des Versprechens) einzurichten.

Wenn sich die Anweisung setTimeout() im gleichen Ereignisthread wie der asynchrone Aufruf befindet, müssen Sie sich keine Gedanken über die Möglichkeit eines Race-Effekts machen. Da Javascript nur als Single-Thread ausgeführt wird, werden die .then() Rückrufe des Versprechens garantiert in einem späteren Ereignisthread ausgelöst.

0