Obtenez l’état de Angular différé?

Avec jQuery différés, j’ai l’habitude d’être capable de vérifier l’état actuel comme ceci:

var defer = $.Deferred(); defer.state(); //Returns the state of the deferred, eg 'resolved' 

Y a-t-il un moyen de faire la même chose pour les différés angulars? (ou même de meilleures promesses)

    Mise à jour :

    En raison du refactoring de $ q, cela est maintenant possible mais pas documenté:

     promise.$$state.status === 0 // pending promise.$$state.status === 1 // resolved promise.$$state.status === 2 // rejected 

    Original :

    Contrairement à la plupart des bibliothèques prometteuses (Bluebird, Q, when, RSVP, etc.), $ q n’expose pas une API d’inspection synchrone.

    Il n’y a aucun moyen d’y parvenir de l’extérieur.

    Vous devez appeler .then sur la promesse et le code dans ce gestionnaire s’exécutera lorsque la promesse sera remplie.

    La réponse à votre question est: oui, il y a un moyen . Les autres réponses couvrent bien les limitations intégrées de $q . Cependant, il est facile d’append une propriété d’état à $q utilisant la fonction de décorateur du service $provide provision .

      $provide.decorator('$q', function ($delegate) { var defer = $delegate.defer; $delegate.defer = function() { var deferred = defer(); deferred.promise.state = deferred.state = 'pending'; deferred.promise.then(function() { deferred.promise.state = deferred.state = 'fulfilled'; }, function () { deferred.promise.state = deferred.state = 'rejected'; }); return deferred; }; return $delegate; }); 

    Mettez ce décorateur à l’intérieur d’un bloc de config , et tous les objects différés et promis basés sur $q auront une propriété d’ state avec la valeur en attente , remplie ou rejetée .

    Découvrez ce plunk


    Sceptique?

    vous modifiez effectivement $ q lui-même, en enveloppant chaque différé avec un autre différé

    En fait, ce n’est pas le cas. $q constructeur original defer() $q est appelé exactement une fois. Il est simplement décoré avec des fonctionnalités supplémentaires en attachant en interne un gestionnaire d’événements via then . [Notez qu’un object différé supplémentaire est instancié à la suite du rappel supplémentaire qui est automatiquement créé avec chaque object différé … ce qui est prévisible, car c’est ainsi que le travail angular fonctionne en interne.]

    cela ne fonctionnerait pas parce que les promesses ne devraient pas être créées avec des promesses différées mais enchaînées qui sont renvoyées par apis

    Notez que ce code va décorer chaque object différé (et donc promise ) créé par le service $q . Cela signifie que toute API qui utilise $ q sera automatiquement décorée avec la propriété state . Donc, quelle que soit la manière dont vous utilisez $q , que ce soit avec une API ou seule, cette solution décore à la fois l’object deferred et la promise , et j’ai fourni le plunk pour le prouver.


    Digne de production?

    Cette approche est testable par unité , il est garanti de ne pas casser d’application utilisant déjà $q , et elle est flexible en ce sens que vous pouvez append plus tard des décorateurs supplémentaires à $q sans modifier l’ancien.

    Actualisé:

    Malheureusement, cela ne semble pas possible avec $q . Vous devrez mettre ce code dans votre méthode then .

     myPromise() .then(function() { // everything in here resolved }, function() { // everything in here rejected }, function() { // everything in here pending (with progress back) }); 

    Autre:

    Ceci est pour la librairie Q pas angular $q mais similaire.

    Angular est inspiré par la bibliothèque Q , consultez la source, ce n’est pas si effrayant. https://github.com/kriskowal/q/blob/v1/q.js

    Vous pouvez utiliser myPromise.inspect().state il y a ['pending', 'rejected', 'fulfilled']

    Vous avez aussi:

     myPromise.isFulfilled(); myPromise.isPending(); myPromise.isRejected(); 

    Découvrez ce JSfiddle et ouvrez la console pour les résultats enregistrés. http://jsfiddle.net/S6LzP/

    Plus granulaire, en regardant la fonction de defer sur la ligne 488:

     function defer() { // if "messages" is an "Array", that indicates that the promise has not yet // been resolved. If it is "undefined", it has been resolved. Each // element of the messages array is itself an array of complete arguments to // forward to the resolved promise. We coerce the resolution value to a // promise using the `resolve` function because it handles both fully // non-thenable values and other thenables gracefully. var messages = [], progressListeners = [], resolvedPromise; var deferred = object_create(defer.prototype); var promise = object_create(Promise.prototype); promise.promiseDispatch = function (resolve, op, operands) { var args = array_slice(arguments); if (messages) { messages.push(args); if (op === "when" && operands[1]) { // progress operand progressListeners.push(operands[1]); } } else { nextTick(function () { resolvedPromise.promiseDispatch.apply(resolvedPromise, args); }); } }; // XXX deprecated promise.valueOf = function () { if (messages) { return promise; } var nearerValue = nearer(resolvedPromise); if (isPromise(nearerValue)) { resolvedPromise = nearerValue; // shorten chain } return nearerValue; }; promise.inspect = function () { if (!resolvedPromise) { return { state: "pending" }; } return resolvedPromise.inspect(); }; if (Q.longStackSupport && hasStacks) { try { throw new Error(); } catch (e) { // NOTE: don't try to use `Error.captureStackTrace` or transfer the // accessor around; that causes memory leaks as per GH-111. Just // reify the stack trace as a ssortingng ASAP. // // At the same time, cut off the first line; it's always just // "[object Promise]\n", as per the `toSsortingng`. promise.stack = e.stack.subssortingng(e.stack.indexOf("\n") + 1); } } // NOTE: we do the checks for `resolvedPromise` in each method, instead of // consolidating them into `become`, since otherwise we'd create new // promises with the lines `become(whatever(value))`. See eg GH-252. function become(newPromise) { resolvedPromise = newPromise; promise.source = newPromise; array_reduce(messages, function (undefined, message) { nextTick(function () { newPromise.promiseDispatch.apply(newPromise, message); }); }, void 0); messages = void 0; progressListeners = void 0; } deferred.promise = promise; deferred.resolve = function (value) { if (resolvedPromise) { return; } become(Q(value)); }; deferred.fulfill = function (value) { if (resolvedPromise) { return; } become(fulfill(value)); }; deferred.reject = function (reason) { if (resolvedPromise) { return; } become(reject(reason)); }; deferred.notify = function (progress) { if (resolvedPromise) { return; } array_reduce(progressListeners, function (undefined, progressListener) { nextTick(function () { progressListener(progress); }); }, void 0); }; return deferred; } 

    Surtout notamment la méthode tout en bas deferred.notify .

    Exemple d’utilisation:

     function requestOkText(url) { var request = new XMLHttpRequest(); var deferred = Q.defer(); request.open("GET", url, true); request.onload = onload; request.onerror = onerror; request.onprogress = onprogress; request.send(); function onload() { if (request.status === 200) { deferred.resolve(request.responseText); } else { deferred.reject(new Error("Status code was " + request.status)); } } function onerror() { deferred.reject(new Error("Can't XHR " + JSON.ssortingngify(url))); } function onprogress(event) { deferred.notify(event.loaded / event.total); } return deferred.promise; } requestOkText("http://localhost:3000") .then(function (responseText) { // If the HTTP response returns 200 OK, log the response text. console.log(responseText); }, function (error) { // If there's an error or a non-200 status code, log the error. console.error(error); }, function (progress) { // Log the progress as it comes in. console.log("Request progress: " + Math.round(progress * 100) + "%"); }); 

    J’ai créé une solution inspirée des réponses de Gil et Travis, qui décore le constructeur Promise avec des méthodes plus proches de l’implémentation Q.

    Notez que cette décoration repose sur l’état Promise.$$state . Ceci a été construit pour Angular 1.6.4, et devrait théoriquement fonctionner jusqu’à 1.3.x, mais aucune garantie à ce sujet ou à venir:

     (function() { 'use ssortingct'; angular .module('your.module.name.goes.here') .config(configBlock); /** @ngInject */ configBlock.$inject = ['$provide']; function configBlock($provide) { $provide.decorator('$q', ['$delegate', function ($delegate) { console.log($delegate); var Promise = $delegate.prototype.constructor; Promise.prototype.inspect = function () { var inspect = {}; switch (this.$$state.status) { case -1: case 0: inspect.state = 'pending'; break; case 1: inspect.state = 'fulfilled'; break; case 2: inspect.state = 'rejected'; break; default: inpsect.state = 'unknown'; } return inspect; }; Promise.prototype.isFulfilled = function () { return this.inspect().state === 'fulfilled'; } Promise.isFulfilled = function (obj) { if (obj.constructor !== Promise) { return true; } return obj.isFulfilled(); } Promise.prototype.isRejected = function () { return this.inspect().state === 'rejected'; } Promise.isRejected = function (obj) { if (obj.constructor !== Promise) { return false; } return obj.isRejected(); } Promise.prototype.isPending = function () { return this.inspect().state === 'pending'; } Promise.isPending = function (obj) { if (obj.constructor !== Promise) { return false; } return obj.isPending(); } return $delegate; }]); } })();