通常、Promiseを使用する場合は、継続コードにthen()
呼び出しを付加し、動作をチェーンするだけでよいことを理解しています。
ただし、promiseでラップされた非同期呼び出しを開始してから、3秒間の$timeout()
を個別に開始して、元のpromiseがまだ完了していない場合にのみUIアクションを実行できるようにします。 (これは低速接続、3Gのモバイルデバイスなどでのみ発生すると予想されます。)
約束が与えられた場合、ブロックまたは待機せずに完了したかどうかを確認できますか?
これはAngularの最近のバージョンで追加されたと思いますが、今では約束に$$ stateオブジェクトがあるようです:
var deferred = $q.defer();
console.log(deferred.promise.$$state.status); // 0
deferred.resolve();
console.log(deferred.promise.$$state.status); //1
コメントに記載されているように、Angularバージョンをアップグレードすると壊れる可能性があるため、これはお勧めしません。
(Angularソースを変更せずにプルリクエストを送信することなく)最善の選択肢は、約束が解決されたかどうかのローカルフラグを保持することです。興味のあるプロミスを設定するたびにリセットし、元のプロミスのthen()
で完了としてマークします。 $timeout
then()
でフラグをチェックして、元のプロミスがまだ解決しているかどうかを確認します。
このようなもの:
var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})
Kris Kowalの実装には、約束の状態をチェックするための他のメソッドが含まれていますが、Angularの$q
の実装には残念ながらこれらが含まれていません。
@shaunhusainが既に述べたように、それは不可能のようです。しかし、おそらくそれは必要ではありません:
// 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);
または多分良い:
var tooSlow = $timeout(doStuff, 3000);
promise.always(tooSlow.cancel);
約束が戻ったかどうかを確認する必要があるという同様の問題がありました。 AngularJSの$watch
関数は、新しい値と古い値の両方が未定義であってもページのレンダリング中に変更を登録するため、外部モデルに保存する価値のあるデータがあるかどうかを確認する必要があります。
それは間違いなくハックですが、私はこれを行います:
$scope.$watch('userSelection', function() {
if(promiseObject.hasOwnProperty("$$v"){
userExportableState.selection = $scope.userSelection;
}
};
$$v
はAngularJSが使用する内部変数であることは知っていますが、解決された約束の指標として非常に信頼できます。 AngularJS 1.2にアップグレードするとどうなるかは誰にもわかりません:-/ 1.2ドキュメントには$q
の改善点は記載されていませんが、Qに近いより優れた機能セットを備えた代替サービスを作成する人がいるかもしれません。
正確なシナリオはわかりませんが、非同期呼び出し(およびプロミスの生成)を行った直後にタイムアウトを設定する方が一般的です。
setTimeout()
ステートメントが非同期呼び出しと同じイベントスレッド内にある場合、競合効果の可能性について心配する必要はありません。 javascriptは厳密にシングルスレッドであるため、プロミスの.then()
コールバックは、後のイベントスレッドで発生することが保証されています。