web-dev-qa-db-fra.com

Comment vérifier si une promesse Angular $ q est résolue

Je comprends qu’en général, on attache simplement le code de continuation avec un comportement d’appel et de chaîne then() lors de l’utilisation de promesses.

Cependant, je souhaite lancer un appel asynchrone encapsulé dans une promesse, puis séparément pour lancer un $timeout() de 3 secondes afin que je puisse effectuer une action d'interface utilisateur, UNIQUEMENT SI la promesse d'origine n'est pas encore terminée. (Je pense que cela ne se produira que sur des connexions lentes, des appareils mobiles en 3G, etc.)

Étant donné une promesse, puis-je vérifier s'il est complet ou non sans blocage ou attente?

83
blaster

Je suppose que cela a été ajouté dans une version récente de Angular mais il semble y avoir maintenant un objet d'état $$ sur la promesse:

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

Comme indiqué dans les commentaires, ceci n’est pas recommandé car cela pourrait casser lors de la mise à niveau de votre version Angular).

46
parliament

Je pense que votre meilleure option en l'état (sans modifier la source Angular et soumettre une demande d'extraction)) est de conserver un indicateur local si la promesse a été résolue. Réinitialisez-la chaque fois que vous configurez la promettez de vous intéresser et marquez-la comme étant complète dans la then() de la promesse originale. Dans la $timeoutthen(), cochez la case pour savoir si la promesse originale a résolu encore ou pas.

Quelque chose comme ça:

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

L'implémentation de Kris Kowal inclut d'autres méthodes pour vérifier l'état de la promesse, mais il semble que l'implémentation de $q Par Angular ne les inclut malheureusement pas.

36
shaunhusain

Cela ne semble pas être possible, comme @shaunhusain l'a déjà mentionné. Mais peut-être que ce n'est pas nécessaire:

// 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);

ou peut-être mieux:

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

J'ai eu un problème similaire où je dois vérifier si une promesse a été retournée. Parce qu'AngularJS est $watch La fonction enregistre une modification lors du rendu de la page, même si les valeurs anciennes et les nouvelles sont indéfinies. Je dois vérifier si des données valent la peine d'être stockées dans mon modèle externe.

C'est définitivement un bidouillage mais je fais ceci:

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

Je le sais $$v est une variable interne utilisée par AngularJS, mais elle s’est avérée assez fiable comme indicateur d’une promesse résolue pour nous. Qui sait ce qui se passera lors de la mise à niveau vers AngularJS 1.2: -/Je ne vois aucune mention d’améliorations à $q dans la documentation 1.2 mais peut-être que quelqu'un écrira un service de remplacement avec un ensemble de fonctionnalités plus proche de Q.

1
PatchCR

Je ne connais pas votre scénario exact, mais il est plus courant de mettre en place un délai d'attente immédiatement après avoir passé l'appel asynchrone (et généré la promesse).

Si l'instruction setTimeout() se trouve dans le même fil d'événements que l'appel asynchrone, vous n'avez pas à vous soucier de la possibilité d'un effet de race. Comme javascript est strictement à thread unique, les rappels de la promesse .then() sont garantis dans un thread d'événement ultérieur.

0
Beetroot-Beetroot