Help us understand the problem. What is going on with this article?

約束って面倒くさい。

More than 3 years have passed since last update.

Promiseを使えばコールバック地獄から解放され、コードの可読性が向上する!!
そう思っていた時期が私にもありました。
コールバック地獄からは解放されたものの可読性についてはいまだに疑問です…

試行錯誤しながら使っているものの、忘れっぽいのでメモっておきます。

Node v4.2.6で検証

メソッドチェーン

jQueryでもおなじみ、みんな大好きメソッドチェーン。
thenはPromiseオブジェクトを返してくれるのでメソッドチェーンができます。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

まずは基本形

'use strict';

Promise.resolve("hogehoge")
.then(function(result){
  console.log("then1", result); // <- result="hogehoge"
  return Promise.resolve(result); // 成功のPromiseオブジェクトを返す
}).then(function(result){
  console.log("then2", result); // <- result="hogehoge"
  return Promise.resolve("fugafuga");  // 成功のPromiseオブジェクトを返す
}).then(function(result){
  console.log("then3", result); // <- result="fugafuga"
  // Promiseオブジェクトを返さない
}).then(function(result){
  console.log("then4", result); // <- result=undefined
  // Promiseオブジェクトを返さない
}).then(function(){
  console.log("then5");
});
result
then1 hogehoge
then2 hogehoge
then3 fugafuga
then4 undefined
then5

エラーがないと上から順番に実行されてくのでわかりやすいですね。

そもそもPromiseオブジェクトを返さなくても動く

(; ・`д・´) ナ、ナンダッテー!!
なんか気持ち悪い。。。

'use strict';

var promise_chain = Promise.resolve()
.then(function(){
  return true;
}).then(function(result){
  console.log("then-bool1", result);
  return false;
}).then(function(result){
  console.log("then-bool2", result);
  return 1;
}).then(function(result){
  console.log("then-int1", result);
  return 0;
}).then(function(result){
  console.log("then-int2", result);
  return "fugafuga";
}).then(function(result){
  console.log("then-string1", result);
  return "";
}).then(function(result){
  console.log("then-string2", result);
  return [];
}).then(function(result){
  console.log("then-array", result);
  return {};
}).then(function(result){
  console.log("then-object", result);
  return null;
}).then(function(result){
  console.log("then-null", result);
});

console.log("start!");
promise_chain.then(function(){
  console.log("end!");
}).catch(function(err){
  console.log("catch", err);
});
start!
then-bool1 true
then-bool2 false
then-int1 1
then-int2 0
then-string1 fugafuga
then-string2
then-array []
then-object {}
then-null null
end!

エラー処理

どこでコケてもcatchが捕捉してくれる安心感

(*>△<)<Promiseチェーンの途中でエラーが起きたらどうしよう!

基本形

'use strict';

Promise.reject("エラーだよ~(o・∇・o)")
.then(function(result){
  console.log("then", result); // <- 呼ばれない
})
.catch(function(err){
  // 失敗のPromiseオブジェクトをcatchする
  console.log("catch", err);
});
result
catch エラーだよ~(o・∇・o)

そんな心配はわりと不要でした。意外とサクッと書けるんだなー。

チェーンの途中でこけても大丈夫!

Promise使うならエラーもPromiseで返した方がいいかもしれませんね。

'use strict';

Promise.resolve("hogehoge")
.then(function(result){
  console.log("then1", result); // <- 呼ばれる
  return Promise.reject("エラーだよ~(o・∇・o)");
})
.then(function(result){
  console.log("then2", result); // <- 呼ばれない
})
.catch(function(err){
  // 失敗のPromiseオブジェクトをcatchする
  console.log("catch", err);
});
result
then1 hogehoge
catch エラーだよ~(o・∇・o)

例外まで受け取れる優れモノ!

これが一番面白い動きかも。
しかしこの仕様を知らなかったせいで、どハマりすることに…(しろめ)

'use strict';

Promise.resolve("hogehoge")
.then(function(result){
  console.log("then1-1", result); // <- 呼ばれる
  throw new Error("(*>△<)<ナーンナーンっっ");
  console.log("then1-2", result); // <- 当然呼ばれない
  return Promise.resolve("fugafuga");
})
.then(function(result){
  console.log("then2", result); // <- 呼ばれない
})
.catch(function(err){
  // throwもcatchする!
  console.log("catch", err);
});
result
then1-1 hogehoge
catch [Error: (*>△<)<ナーンナーンっっ]

例外の罠

PromiseでくるまれるとPromiseのcatchですべて受けてしまうので注意。
これのせいで1時間ほどハマりしました。。

ダメな例

promise_exception_ng.js
'use strict';

function p_exception() {
  return (new Promise(function(resolve, reject){
    var hoge = null;
    resolve(hoge.fuga); // <- 例外発生
  }));
}

try {
  p_exception().then(function(result){
    console.log("then", result);
  });
} catch(e) {
  console.log("catch", e); // <- ここにこない!
}
result
$ node promise_exception_ng.js
$ echo $?
0

OKな例

何が起こるかわからないのでPromiseでくるんだらとりあえずcatchは書いておいたほうがよさそう。

'use strict';

function p_exception() {
  return (new Promise(function(resolve, reject){
    var hoge = null;
    resolve(hoge.fuga); // <- 例外発生
  }));
}

p_exception()
.then(function(result){
  console.log("then", result);
})
.catch(function(err){
  console.log("catch", err);
});
result
catch [TypeError: Cannot read property 'fuga' of null]

だがしかし…

当然っちゃ当然ですが、Promiseでくるんでない部分の例外は従来のtry~catchで処理しなければならない。
(*>△<)<面倒くさいー!

'use strict';

function n_exception() {
  var hoge = null;
  var piyo = hoge.fuga; // <- 例外発生
  return (new Promise(function(resolve, reject){
    resolve(piyo);
  }));
}

try {
  n_exception()
  .then(function(result){
    console.log("then", result);
  })
  .catch(function(err){
    console.log("catch", err); // <- ここにこない!
  });
} catch(e) {
  console.log("catch2", e); // <- ここで無事catchされる
}
catch2 [TypeError: Cannot read property 'fuga' of null]

終わりだよ~(o・∇・o)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away