目次へ戻る


9) アンチパターン

Promiseオブジェクトをだいぶ理解いただけたでしょうか。 次はついうっかり使ってしまいがちなアンチパターンを紹介します。

ここで紹介するものは以下のパターンを参考にした ES6 Promise版です。

Promise Anti-patterns

http://taoofcode.net/promise-anti-patterns/

Nested Promises

taskA().then(function(taskAResult){
  taskB().then(function(taskBResult){
    taskC().then(function(taskCResult){
      doSomething(taskAResult, taskBResult, taskCResult);
    });
  });
});
  • 返却された値を全て知るためにthen()がネストしています

fix

all()を使えば返却された値を全て知る事ができます。

Promise.all([taskA(),taskB(),taskC()])
  .then(function(values){
    doSomething(values);
  })
;

plunker

The Broken Chain

function getPromise(){
  return new Promise(function(resolve,reject){
    resolve(1);
  });
}

function callPromise(){
  var promise = getPromise();
  promise.then(function(){ doSomething(); });
  return promise;
}

var result = callPromise();

  • then()で返却されたPromiseオブジェクトが使用されないためメソッドチェインが途切れています
  • このためdoSomething()で発生したエラーをハンドリングできません

fix

then()の結果を返却すると、呼び出し側でthen()のメソッドチェインをつなげる事ができます。

function callPromise(){
  var promise = getPromise();
  return promise.then(function(){
    // ...
  });
}

callPromise().then(function(){
  console.info('fulfilled');
});

plunker

The Collection Kerfuffle

function task(value){
  return new Promise(function(resolve,reject){
    resolve(value);
  });
}

var numbers = [1,2,3];
var results = [];

function recursive(index){
  if (index >= numbers.length) {
    return;
  }
  task(numbers[index])
    .then(function(result){
      results.push(result);
      recursive(index + 1);
    })
  ;
}

recursive(0);
  • 再帰処理が目的を分かりづらくさせています

fix

all()が複数のPromiseオブジェクトを並列で実行できる事を思い出しましょう。

function task(value){
  return new Promise(function(resolve,reject){
    resolve(value);
  });
}

var numbers = [1,2,3];
var results = [];

var tasks = numbers.map(function(number){
  return task(number);
});

Promise.all(tasks)
  .then(function(values){
    results = values;
  })
;

plunker

逐次実行したい場合はreduce()を使いましょう。

var tasks = values.map(function(value){
  return task(value).then(function(value){
    results.push(value);
  });
});

var reduced = tasks.reduce(function(promise, task){
  return promise.then(task);
}, Promise.resolve());

reduced.then(function(){
  console.log(results);
});

plunker

The Overly Keen Error Handler

task().then(function(){
  throw new Error('unexpected');
},function(error){
  console.log(error.message);
});
  • then(onFulfilled, onRejected)onFulfilled内のエラーをハンドリングできません

fix

エラーをハンドリングするには一番最後のthen()onRejectedだけ指定します。

task()
  .then()
  .then(null, function(){
    console.log(error.message);
  })
;

plunker

またはcatch()を使います。

task()
  .then()
  .catch(function(error){
    console.log(error.message);
  })
;

plunker

The Forgotten Promise


Promise.resolve()
  .then(function(){
      return new Promise(function(resolve){
        resolve(1);
      });
  })
  .then(function(){
      return new Promise(function(resolve){
        resolve(2);
      });
  })
;
  • then()はPromiseオブジェクトを生成して返すため、自分でPromiseオブジェクトを生成する必要はありません

fix

値を返却します


Promise.resolve()
  .then(function(){
      return 1;
  })
  .then(function(){
      return 2;
  })
;

plunker


前のページ 次のページ