LoginSignup
30
29

More than 5 years have passed since last update.

約束って面倒くさい。

Last updated at Posted at 2016-02-18

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)

30
29
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
29