webentwicklung-frage-antwort-db.com.de

Erhalten Sie den Status von Angular zurückgestellt?

Mit jQuery-Verschiebungen kann ich den aktuellen Status wie folgt überprüfen:

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

Gibt es eine Möglichkeit, das gleiche für Angular-Deferreds zu tun? (oder noch bessere Versprechen)

39
Evan Hobbs

Update :

Aufgrund der Umgestaltung von $ q ist dies nun möglich, jedoch nicht dokumentiert:

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

Original :

Im Gegensatz zu den meisten Versprechenbibliotheken (Bluebird, Q, when, RSVP usw.) stellt $ q keine synchrone Überprüfungs-API bereit. 

Dies kann von außen nicht erreicht werden.

Sie müssen .then auf dem Versprechen aufrufen, und der Code in diesem Handler wird ausgeführt, wenn das Versprechen erfüllt ist.

82

Die Antwort auf Ihre Frage lautet: ja, es gibt einen Weg . Die anderen Antworten decken die integrierten Einschränkungen von _$q_ gut ab. Es ist jedoch einfach, eine state -Eigenschaft zu _$q_ hinzuzufügen, indem Sie die Dekorationsfunktion des _$provide_ -Dienstes verwenden .

_  $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;
  });
_

Fügen Sie diesen Dekorator in einen config - Block ein, und alle _$q_ - instanziierten zurückgestellt und versprochen - Objekte haben einen state -Eigenschaft mit dem Wert ausstehend, erfüllt oder abgelehnt.

Schauen Sie sich this plunk an


Skeptisch?

Sie ändern effektiv $ q selbst, indem Sie jede zurückgestellte mit einer anderen zurückgestellten umschließen

Eigentlich ist das nicht der Fall. _$q_ 's ursprünglicher Konstruktor defer() wird genau einmal aufgerufen. Es wird einfach mit zusätzlichen Funktionen ausgestattet, indem ein Ereignishandler über then intern angehängt wird. [Beachten Sie, dass ein zusätzliches defer - Objekt als Ergebnis des zusätzlichen then - Rückrufs instanziiert wird, der automatisch mit jedem aufgeschoben Objekt ... erstellt wird, das zu ist zu erwarten, weil dies ist, wie angular intern funktioniert.]

das würde nicht funktionieren, da Versprechen nicht mit verzögerten, sondern mit verketteten Versprechen erstellt werden sollten, die von apis zurückgegeben werden

Beachten Sie, dass dieser Code jedes zurückgestellte (und damit promise - Objekt) schmückt, das vom _$q_ -Dienst erstellt wird. Dies bedeutet, dass jede API, die $ q verwendet, automatisch mit der Eigenschaft state dekoriert wird . Unabhängig davon, wie Sie _$q_ verwenden, ob mit einer API oder für sich allein, ziert diese Lösung sowohl das Objekt deferred als auch das Objekt promise, und ich habe the) angegeben plunk um es zu beweisen.


Produktionswürdig?

Dieser Ansatz ist Unit-testbar , es ist garantiert, dass keine Anwendung unterbrochen wird, die bereits _$q_ und es ist flexibel in dem Sinne, den Sie später hinzufügen könnten zusätzliche Dekoratoren zu _$q_, ohne die alten zu ändern.

34
Gil Birman

Aktualisierte:

Leider sieht das mit $q nicht so aus. Sie müssen diesen Code in Ihre then-Methode einfügen.

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

Andere:

Dies ist für die Q-Bibliothek nicht $q des Winkels, sondern ähnlich.

Angular ist von der Q-Bibliothek inspiriert. Schauen Sie sich die Quelle an. https://github.com/kriskowal/q/blob/v1/q.js

Sie können myPromise.inspect().state verwenden, es gibt ['pending', 'rejected', 'fulfilled']

Sie haben auch:

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

Schauen Sie sich dieses JSfiddle an und öffnen Sie die Konsole für protokollierte Ergebnisse . http://jsfiddle.net/S6LzP/

Genauer gesagt, Betrachten der Funktion defer in Zeile 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 string ASAP.
            //
            // At the same time, cut off the first line; it's always just
            // "[object Promise]\n", as per the `toString`.
            promise.stack = e.stack.substring(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 e.g. 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;
}

Meistens die Methode ganz unten deferred.notify.

Verwendungsbeispiel:

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.stringify(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) + "%");
});
1
Travis

Ich habe eine von Gil und Travis 'Antworten inspirierte Lösung gefunden, die den Promise-Konstruktor mit Methoden schmückt, die näher an der Q-Implementierung liegen.

Beachten Sie, dass diese Dekoration auf Promise.$$state basiert. Dies wurde für Angular 1.6.4 entwickelt und sollte theoretisch bis 1.3.x funktionieren, jedoch keine Garantien für diese oder zukünftige Versionen:

(function() {
    'use strict';

    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;
        }]);
    }
})();
0
p0lar_bear