Promise
Javascriptの非同期実行補助機能。みたいな
code:js
.then(function(response){
return response.json();
})
.then(function(myJson){
console.log(JSON.stringify(myJson));
});
みたいな物。
非同期実行される関数の完了後に動作するメソッド(コールバック)を、後付けで登録する感じ
この仕組みを自前で作る時にPromiseを使う
基本的な使い方
code:js
function sleep(ms){
return new Promise(function(resolve, reject){
setTimeout(resolve, ms);
});
}
sleep(1000).then(function(){ console.log('good morning!'); });
非同期の作業を開始して、完了した際に resolve 関数 (成功した場合) もしくは reject 関数 (エラーが発生した場合) のいずれか一方を呼び出します。
Promiseに食わせた関数にはresolveとrejectと言う関数が渡されるので、正常終了したならresolve()、異常終了したならreject()を呼ぶようにする
複数のPromiseの全てが完了するのを待ち受けたいなら、Promise.allを使う
code:js
function hoge(){
return new Promise((resolve, reject)=>{ doSomething(); });
}
.thenのアンチパターン
Promise#thenで数珠つなぎにして処理を書けるが、このthenメソッドは、新しいPromiseオブジェクトを返している。
なので、以下の例だと振る舞いが異なるので注意
code:js
// 1: それぞれの then は同時に呼び出される
const aPromise = new Promise((resolve) => {
resolve(100);
});
aPromise.then((value) => {
return value * 2;
});
aPromise.then((value) => {
return value * 2;
});
aPromise.then((value) => {
console.log("1: " + value); // => 100
});
// vs
// 2: then はpromise chain通り順番に呼び出される
const bPromise = new Promise((resolve) => {
resolve(100);
});
bPromise.then((value) => {
return value * 2;
}).then((value) => {
return value * 2;
}).then((value) => {
console.log("2: " + value); // => 100 * 2 * 2
});
Promiseチェーン
thenチェーンの中にPromiseを混ぜ込む。Promiseの順次実行などの実現。
thenに渡す関数が、Promise型を復帰するか否かで振る舞いが変わるのを利用する。
値を返した場合、 then によって返される Promise は返値をその値として解決します。
pending 状態の Promise オブジェクトを返した場合、 then によって返された Promise の解決/拒絶は、ハンドラーによって返された Promise の解決/拒絶結果に依存します。
code:js
a = new Promise(resolve=>{
console.log(1)
})
.then(()=>{
return new Promise(resolve=>{
console.log(2);
resolve();
});
Deferred
Promiseが値を抽象化したオブジェクトなのに対して、 Deferredはまだ処理が終わってないという状態や操作を抽象化したオブジェクトである違いがでているのかもしれません。
言い換えると、 Promiseはこの値は将来的に正常な値(FulFilled)か異常な値(Rejected)が入るというものを予約したオブジェクトなのに対して、 Deferredはまだ処理が終わってないということを表すオブジェクトで、 処理が終わった時の結果を取得する機構(Promise)に加えて処理を進める機構をもったものといえるかもしれません。
多分、より厳密にPromiseの遅延実行出来る点に着目した実装。だと思う
実装例
code:js
class Deferred {
constructor(){
this.promise = new Promise( (resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
}
resolve(value){
this._resolve(value);
}
reject(reason){
this._reject(reason);
}
}
function sleep(ms){
const deferred = new Deferred();
setTimeout(_=>{deferred.resolve()}, ms);
return deferred.promise;
}
sleep(1000).then(_=>console.log('wake up!'));
(とはいえこの実装を試したら、this._resolve == nullの状態でthis._resolve()が実行されたケースがあるので、いまいち)