たとえば、ページが Google Maps API を呼び出すときに Promise が使用されます。
function success(position){ var cords = position.coords; console.log(coords.latitude + coords.longitude); } function error(err){ console.warn(err.code+err.message) } navigator.geolocation.getCurrentPosition(success, error);
■複数の非同期メソッドの扱い方
順番に実行する必要がある非同期メソッドが多数ある場合はどうすればよいでしょうか? async1(成功、失敗)、async2(成功、失敗)、...asyncN(成功、失敗)、どう対処すればいいでしょうか?
最も単純なものは次のように書くことができます:
async1(function(){ async2(function(){ ... asyncN(null, null); ... }, null) }, null)
上記のコードは保守が比較的困難です。
すべての非同期メソッドが実行された後に通知を表示させることができます。
var counter = N; function success(){ counter--; if(counter === 0){ alert('done'); } } async1(success); async2(success); ... asyncN(success);
■約束と延期とは
Deferred は非同期操作の結果を表し、操作結果とステータスを表示するインターフェイスを提供し、操作結果を取得できる Promise インスタンスを提供します。遅延により動作ステータスが変更される可能性があります。
Promise は、関連する遅延と対話するためのインターフェイスを提供します。
遅延を作成する場合、それは保留状態と同等です。
解決メソッドが実行されると、解決された状態と同等になります。
拒否メソッドを実行すると拒否された状態に相当します。
遅延を作成した後にコールバック関数を定義できます。コールバック関数は、解決済みおよび拒否されたステータス プロンプトを取得した後に実行を開始します。非同期メソッドは、コールバック関数がどのように動作するかを知る必要はありません。解決済みまたは拒否されたステータスを取得した後に実行を開始するようにコールバック関数に通知するだけで済みます。
■基本的な使い方
→ 遅延作成
var myFirstDeferred = $q.defer();
ここで、遅延された myFirstDeferred のステータスは保留中になります。次に、非同期メソッドの実行が成功すると、ステータスは解決済みになります。非同期メソッドが失敗すると、ステータスは拒否されます。
→ このエラーを解決または拒否します
次のような非同期メソッドがあるとします: async(success, Failure)
async(function(value){ myFirstDeferred.resolve(value); }, function(errorReason){ myFirstDeferred.reject(errorReason); })
AngularJS では、$q の解決と拒否はコンテキストに依存せず、大まかに次のように記述できます:
async(myFirstDeferred.resolve, myFirstDeferred.reject);
→ 遅延で Promise を使用
var myFirstPromise = myFirstDeferred.promise; myFirstPromise .then(function(data){ }, function(error){ })
遅延には複数の Promise を含めることができます。
var anotherDeferred = $q.defer(); anotherDeferred.promise .then(function(data){ },function(error){ }) //调用异步方法 async(anotherDeferred.resolve, anotherDeferred.reject); anotherDeferred.promise .then(function(data){ }, function(error){ })
上記では、非同期メソッド async が正常に実行されると、両方の成功メソッドが呼び出されます。
→ 通常、非同期メソッドを関数にラップします
function getData(){ var deferred = $q.defer(); async(deferred.resolve,deferred.reject); return deferred.promise; } //deferred的promise属性记录了达到resolved, reject状态所需要执行的success和error方法 var dataPromise = getData(); dataPromise .then(function(data){ console.log('success'); }, function(error){ console.log('error'); })
成功コールバック関数のみに注目する場合はどのように記述すればよいでしょうか?
dataPromise .then(function(data){ console.log('success'); })
エラーコールバック関数のみに注目する場合はどのように記述すればよいでしょうか?
dataPromise .then(null, function(error){ console.log('error'); }) 或 dataPromise.catch(function(error){ console.log('error'); })
成功または失敗に関係なく、コールバックが同じ結果を返したらどうなるでしょうか?
var finalCallback = function(){ console.log('不管回调成功或失败都返回这个结果'); }
dataPromise.then(finalCallback, FinalCallback);
または
dataPromise.finally(finalCallback);
■バリューチェーン
deferred.resolve を使用して値を返す非同期メソッドがあるとします。
function async(value){ var deferred = $q.defer(); var result = value / 2; deferred.resolve(result); return deferred.promise; }
返される内容は約束なので、その都度続行できます。
var promise = async(8) .then(function(x){ return x+1; }) .then(function(x){ return x*2; }) promise.then(function(x){ console.log(x); })
上記では、resolve からの値が各チェーンの実際のパラメーターになります。
■ プロミスチェーン
function async1(value){ var deferred = $q.defer(); var result = value * 2; deferred.resolve(result); return deferred.promise; } function async2(value){ var deferred = $q.defer(); var result = value + 1; deferred.resolve(result); return deferred.promise; } var promise = async1(10) .then(function(x){ return async2(x); }) promise.then(function(x){ console.log(x); })
もちろん、より読みやすい書き方は次のとおりです。
function logValue(value){ console.log(value); } async1(10) .then(async2) .then(logValue);
async1メソッドの戻り値はthenメソッド内のsuccessメソッドの実パラメータとなります。
例外をキャッチするという観点からは、次のように書くこともできます:
async1() .then(async2) .then(async3) .catch(handleReject) .finally(freeResources);
■ $q.reject(reason)
このメソッドを使用すると、遅延がエラー状態で表示され、エラーの理由が示される可能性があります。
var promise = async().then(function(value){ if(true){ return value; } else { return $q.reject('value is not satisfied'); } })
■ $q.when(値)
値を含む Promise を返します。
function getDataFromBackend(query){ var data = searchInCache(query); if(data){ return $q.when(data); } else { reutrn makeAasyncBackendCall(query); } }
■ $q.all(promisesArr)
すべての Promise が実行されるまで待ちます。
var allPromise = $q.all([ async1(), async2(), ... asyncN(); ]) allProise.then(function(values){ var value1 = values[0], value2 = values[1], ... valueN = values[N]; console.log('all done'); })
以上がこの記事の詳細な内容であり、皆様の学習のお役に立てば幸いです。