目次へ戻る


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

plunker

メソッドチェイン

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'
  })
;

plunker

thenの中で値を返さない場合

値を返さない場合は、空の値でresolve()された状態が次のthen()に渡されます。

promise
  .then(function(){
  })
  .then(function(value){
    console.info(value); // undefined
  })
;

plunker

thenの中でPromiseを返す場合

then()の中でPromiseオブジェクトを返すと、そのまま次のthen()に渡されます。

promise
  .then(function(){
    return new Promise(function(resolve,reject){
      resolve(2);
    });
  })
  .then(function(value){
    console.info(value); // 2
  })
;

plunker

promise
  .then(function(){
    return new Promise(function(resolve,reject){
      reject(new Error('cancel'));
    });
  })
  .then(null,function(error){
    console.log(error.message); // 'cancel'
  })
;

plunker

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'
  })
;

plunker

onRejectedとcatch()の違い

rejected な状態を拾うには、then()の引数onRejectedcatch()のどちらを使うのが良いのでしょうか?

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'
  })
;

plunker

予想通り resolved な状態が拾えます。 ではonFulfilledの中でエラーが発生した場合はどうでしょうか?

task()
  .then(function(){})
  .then(function(){
    throw new Error('unexpected');
  }, function(error){
    console.log(error.message); // 実行されない
  })
;

// ブラウザでエラーが発生
// Uncaught (in promise) Error: unexpected

plunker

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'
  })
;

plunker


前のページ 次のページ