5) Thenable
Promiseオブジェクトはthen()
メソッドを持ちます。then()
にはPromiseオブジェクトの状態が fulfilled または rejected に変化した時の処理をコールバック関数として渡すことができます。この事を Thenable と呼びます。
thenの引数
then()
はonFulfilled
onRejected
の2つの引数を取ります。ここには処理が成功した時、失敗した時、それぞれのコールバックを渡します。
promise.then(onFulfilled, onRejected)
promise
.then(
function(){ console.info('fulfilled'); },
function(){ console.error('rejected'); }
);
thenはPromiseオブジェクトを生成する
then()
は呼ばれるごとに新しいPromiseオブジェクトを生成して返します。
var promise = new Promise(function(resolve,reject){
resolve(1);
});
var a = promise.then();
var b = promise.then();
// 常に新しいPromiseオブジェクトが生成される
console.log(a === b); // false
メソッドチェイン
then()
はPromiseオブジェクトを返すためメソッドチェインでいくつも処理をつなげる事ができます。
promise
.then(function(){})
.then(function(){})
.then(function(){})
...
;
thenの中で値を返す場合
then()
に渡したコールバックの中で値を返すとresolve([値])
されたPromiseが次のthen()
に渡されます。
promise
.then(function(){
return 'one';
})
.then(function(){
return 'two';
})
.then(function(value){
console.info(value); // 'two'
})
;
thenの中で値を返さない場合
値を返さない場合は、空の値でresolve()
された状態が次のthen()
に渡されます。
promise
.then(function(){
})
.then(function(value){
console.info(value); // undefined
})
;
thenの中でPromiseを返す場合
then()
の中でPromiseオブジェクトを返すと、そのまま次のthen()
に渡されます。
promise
.then(function(){
return new Promise(function(resolve,reject){
resolve(2);
});
})
.then(function(value){
console.info(value); // 2
})
;
promise
.then(function(){
return new Promise(function(resolve,reject){
reject(new Error('cancel'));
});
})
.then(null,function(error){
console.log(error.message); // 'cancel'
})
;
rejectedな状態を拾う
メソッドチェインのどこかで rejected な状態になった時(およびエラーが発生した時)は次のthen()
へと処理が移ります。onRejected
が指定されていない場合はその次のthen()
へ処理が移ります。この仕組みを利用して、メソッドチェインの最後でまとめて rejected な状態を拾う事ができます。
function task(){
return new Promise(function(resolve,reject){
resolve(1);
});
}
function failedTask() {
return new Promise(function(resolve,reject){
reject(new Error('abort'));
});
}
task()
.then(failedTask)
.then(function(){})
.then(function(){})
.catch(function(error){
console.log(error.message); // 'abort'
})
;
onRejectedとcatch()の違い
rejected な状態を拾うには、then()
の引数onRejected
とcatch()
のどちらを使うのが良いのでしょうか?
then()
の引数onRejected
を使う
function task(){
return new Promise(function(resolve,reject){
resolve(1);
});
}
function failedTask(){
return new Promise(function(resolve,reject){
reject(new Error('abort'));
});
}
task()
.then(failedTask)
.then(null, function(error){
console.log(error.message); // 'abort'
})
;
予想通り resolved な状態が拾えます。
ではonFulfilled
の中でエラーが発生した場合はどうでしょうか?
task()
.then(function(){})
.then(function(){
throw new Error('unexpected');
}, function(error){
console.log(error.message); // 実行されない
})
;
// ブラウザでエラーが発生
// Uncaught (in promise) Error: unexpected
then(onFulfilled, onRejected)
のように書いた場合、onFulfilled
で発生したエラーをonRejected
で拾う事はできません。このため、想定外のエラーも rejected として扱いたい場合はthen(null, onRejected)
または catch()
を使ったほうが良いと言えるでしょう。
catch()
を使う
task()
.then(function(){})
.then(function(){
throw new Error('unexpected');
})
.catch(function(error){
// onFulfilledで発生したエラーも拾える
console.log(error.message); // 'unexpected'
})
;