環境
node:v8.11.3
非同期処理について
nodeを使ってapi作ってるときに、routeからサービスに行って次にdaoに行って~みたいな流れの中で、比較的少し時間がかかるDB処理や物理ファイル関連の処理やADサーバの処理とかで順番に処理をさせるために関数を非同期にしてawait使っていたんだけど、
それだと全ての関数にasyncつけなきゃいけなかったり、awaitつける必要が出てくるので、いろいろ面倒になってくる。
当然、daoの部分が非同期関数なら、それを呼び出すサービスの関数の中でawaitをつける必要があり、awaitを使う関数もまた非同期にしなきゃいけなくて、またその関数を呼び出す関数も非同期にしなきゃいけなくなってしまうってことになる。
つまり、コントローラー、サービス、リポジトリ全て非同期になってしまう。
awaitつけて呼び出そうとしたら、「ここ非同期じゃないやんけ。。。」って怒られてasyncのつけ忘れを直す機会がしばしばあるのが面倒だけど、個人的にはそんな嫌いじゃない。でもどいつもこいつも非同期になるのはなんか気持ち悪いですねぇ。。。(至言)
一見、関数をasyncにして呼び出すときはawaitつけるだけで済むのでラクじゃんって思うかもしれないが、規模が大きくなっていくことを考えるとそれはよろしくなかった。(PLに感謝)
プログラム
const HogeController = function(args) {
return {
doCalc: function() {
return new Promise(function (resolve, reject) {
const a = 1;
const b = 2;
const result = a + b;
resolve(result);
});
},
firstProcess: function() {
this.doCalc().then(function(value){
console.log(value);
})
}
};
};
module.exports = HogeController;
const hogeCon = new HogeController();
hogeCon.firstProcess();
今回はPromise/thenの例なのでわざわざmysqlモジュールとか使ってDB接続処理を書かずに足し算しかしてないけど、DB処理とか物理ファイルダウンロードとか、処理に少し時間がかかるものに対して、Promsieで囲って待ってくれるようにして、処理が終わったら、thenの中が呼ばれて、次の処理ができるようになって、順番が守られる。
もし、サービスクラス以降で非同期になっているのであれば、リポジトリクラスの各メソッドでreturn new Promoseで囲って任意のタイミングでresolve()してしまえば、サービスクラスを使っているルートの部分が非同期じゃなくても、then()で得た値がpendingになることはない。
expressとか使ってapi作る時に、通常のDB処理apiとは別に最初にadサーバからデータを持ってくる必要があった場合には、thenの中が呼ばれたあとに、next()ってやって次の処理をさせるようにしたりしたこともあった。
その他
もちろんasync/awaitは使ってもよいのだが、それを使うのはサービスクラスまでにしておく。
ルーティングに入る前の段階もasync/await使ってもよい。