JQueryの遅延オブジェクトを使用すると、次のように現在の状態を確認できます。
var defer = $.Deferred();
defer.state(); //Returns the state of the deferred, eg 'resolved'
Angular deferredsに対して同じことを行う方法はありますか?
更新:
文書化されていませんが、$ qのリファクタリングにより、これが可能になりました。
promise.$$state.status === 0 // pending
promise.$$state.status === 1 // resolved
promise.$$state.status === 2 // rejected
オリジナル:
ほとんどのpromiseライブラリ(Bluebird、Q、when、RSVPなど)とは異なり、$ qは同期検査APIを公開しません。
これを外部から達成する方法はありません。
Promiseで.then
を呼び出す必要があり、promiseが満たされるとそのハンドラーのコードが実行されます。
あなたの質問に対する答えは:はい、方法がありますです。他の答えは、_$q
_の組み込み制限をうまくカバーしています。ただし、状態プロパティを_$q
_に追加するのは簡単です。the _$provide
_ サービスのデコレータ関数 =。
_ $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;
});
_
このデコレータをconfig
ブロック内に配置すると、すべての_$q
_- instantiateddeferredおよびpromiseオブジェクトにstate
プロパティと値pending、fulfilled、またはrejected。
$ q自体を効果的に変更し、すべての遅延オブジェクトを別の遅延オブジェクトでラップします
実際にはそうではありません。 _$q
_の元のdefer()
コンストラクターは1回だけ呼び出されます。 then
を介してイベントハンドラーを内部的にアタッチすることにより、単に追加機能で装飾されます。 [追加のdefer
オブジェクトは、各deferredオブジェクトで自動的に作成される追加のthen
コールバックの結果としてインスタンス化されることに注意してください...これはangularが内部的に機能する方法です。]
これは機能しません。なぜなら、Promiseは遅延で作成されるべきではなく、apisから返されるPromiseからチェーンされるべきだからです。
このコードは、_$q
_サービスによって作成されるevery deferred(したがってpromise
オブジェクト)を修飾することに注意してください。これは、$ qを使用するAPIがstate
プロパティで自動的に修飾されることを意味しますしたがって、_$q
_の使用方法に関係なく、何らかのAPIを使用するか、独自のAPIを使用するかにかかわらず、このソリューションはdeferred
オブジェクトとpromise
の両方を装飾し、 それを証明するためのプランク 。
このアプローチは単体テスト可能であり、_$q
_を既に使用しているアプリケーションを壊さないことを保証し、そしてそれは柔軟です後で古いデコレータを変更せずに_$q
_にデコレータを追加できます。
残念ながら、これは_$q
_では可能なようには見えません。このコードをthen
メソッド内に配置する必要があります。
_myPromise()
.then(function() {
// everything in here resolved
},
function() {
// everything in here rejected
},
function() {
// everything in here pending (with progress back)
});
_
これは、Angularの_$q
_ではなく、Qライブラリ用です。
AngularはQ
ライブラリに触発され、ソースをチェックしてください。実際はそれほど怖いものではありません。 https://github.com/kriskowal/q/blob/v1/q.js
myPromise.inspect().state
を使用できます_['pending', 'rejected', 'fulfilled']
_があります
あなたも持っています:
_myPromise.isFulfilled();
myPromise.isPending();
myPromise.isRejected();
_
このJSfiddleをチェックして、ログに記録された結果のコンソールを開きます。 http://jsfiddle.net/S6LzP/
より細かく、488行目のdefer
関数を見ると:
_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;
}
_
最も顕著なのは、一番下の_deferred.notify
_のメソッドです。
使用例:
_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) + "%");
});
_
Gil and Travisの回答に触発されたソリューションを作成しました。このソリューションは、PromiseコンストラクターをQ実装により近いメソッドで装飾します。
この装飾はPromise.$$state
に依存していることに注意してください。これはAngular 1.6.4のために構築されたもので、理論的には1.3.xまで機能しますが、そのリリースまたは将来のリリースでは保証されません。
(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;
}]);
}
})();