teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

おまけ追加

2018/03/21 07:35

投稿

miyabi-sun
miyabi-sun

スコア21445

answer CHANGED
@@ -14,4 +14,135 @@
14
14
 
15
15
  特にダメそうなのがk.tadaさんも仰ってるmysql2のqueryにコールバック関数乗せちゃってる箇所。
16
16
  コールバックがない場合mysql2はPromiseを返す挙動になっているはずですが、
17
- コールバック関数を指定した場合の挙動は私は把握してませんね…もし気になるならソースコードを実際に読んでみてください。
17
+ コールバック関数を指定した場合の挙動は私は把握してませんね…もし気になるならソースコードを実際に読んでみてください。
18
+
19
+ ---
20
+
21
+ 【おまけ】 完成版コードへの軽いレビュー
22
+
23
+ お疲れ様でした、ぐっと見やすい良いコードになりましたね。
24
+ 折角なのでこの完成版コードを軽く見ていきます。
25
+
26
+ - poolは直接queryメソッド叩いて使える
27
+ - Promise.allと併用して並列処理っぽく
28
+ - Promiseをリスト操作で生成する
29
+ - asyncで作った関数はresolve, rejectを意識する
30
+
31
+ > poolは直接queryメソッド叩いて使える
32
+
33
+ もう見たまんまです。
34
+ connを取り出しても良いですが、このまま使った方が楽ちんでしょう。
35
+
36
+ ```JavaScript
37
+ const test = async () => {
38
+ const [rows_1, fields_1] = await pool.query('SELECT * FROM hoge_1');
39
+ console.log(rows_1);
40
+
41
+ const [rows_2, fields_2] = await pool.query('SELECT * FROM hoge_2');
42
+ console.log(rows_2);
43
+
44
+ const [rows_3, fields_3] = await pool.query('SELECT * FROM hoge_3');
45
+ console.log(rows_3);
46
+
47
+ await pool.end();
48
+ }
49
+ ```
50
+
51
+ > Promise.allと併用して並列処理っぽく
52
+
53
+ まずはこのコードをデベロッパーツールに突っ込んで結果を見て下さい。
54
+ 戻り値がPromiseであることが確認出来ます。
55
+ (Numberの配列なんで即resolvedしてますが)
56
+
57
+ ```JavaScript
58
+ Promise.all([123]);
59
+ // Promise {<resolved>: Array(1)}
60
+ ```
61
+
62
+ つまり、このように書けば並列処理になります。
63
+ これならばpoolでコネクションを複数本引っ張った意味も出来るでしょう。
64
+ (ちょっとこれを走らせて速度を確認してみてください。)
65
+
66
+ ```JavaScript
67
+ const test = async () => {
68
+ const results = await Promise.all([
69
+ pool.query('SELECT * FROM hoge_1'),
70
+ pool.query('SELECT * FROM hoge_2'),
71
+ pool.query('SELECT * FROM hoge_3')
72
+ ]);
73
+ console.log(results);
74
+
75
+ await pool.end();
76
+ }
77
+ ```
78
+
79
+ > Promiseをリスト操作で生成する
80
+
81
+ pool.query何回も実行してますが、これはダサいです。
82
+ sqlの配列から動的に作るようにしましょう。
83
+
84
+ 前項ではコードがキモい感じでしたが、
85
+ 多少そのキモさが和らいでるのが確認できます。
86
+
87
+ ```JavaScript
88
+ const test = async () => {
89
+ const sqls = [
90
+ 'SELECT * FROM hoge_1',
91
+ 'SELECT * FROM hoge_2',
92
+ 'SELECT * FROM hoge_3'
93
+ ];
94
+ const promises = sqls.map(sql => pool.query(sql));
95
+ const results = await Promise.all(promises);
96
+ console.log(results);
97
+
98
+ await pool.end();
99
+ }
100
+ ```
101
+
102
+ > asyncで作った関数はresolve, rejectを意識する
103
+
104
+ これは実践とはかけ離れた条件下なので、既にやっていることかもしれませんが、
105
+ asyncはawaitの逆、つまり絶対にpromiseを返す関数として振る舞います。
106
+
107
+ - returnで値を返せばresolve(value)と等価
108
+ - throwで例外を投げればreject(err)と等価
109
+
110
+ 特にtestの外でコネクションを張っておきながら、testの中で閉じるのもおかしな話です。
111
+ 実践を見据えてその辺を解消していきます。
112
+
113
+ ```JavaScript
114
+ const mysql = require('mysql2/promise');
115
+
116
+ const pool = mysql.createPool({
117
+ host: 'localhost',
118
+ user: 'foo',
119
+ password: '',
120
+ database: 'test'
121
+ });
122
+
123
+ const test = pool => {
124
+ const sqls = [
125
+ 'SELECT * FROM hoge_1',
126
+ 'SELECT * FROM hoge_2',
127
+ 'SELECT * FROM hoge_3'
128
+ ];
129
+ return Promises.all(sqls.map(sql => pool.query(sql)));
130
+ }
131
+
132
+ test(pool)
133
+ .then(results => {
134
+ console.log(results);
135
+ pool.end();
136
+ })
137
+ .catch(err => {
138
+ console.error(err);
139
+ pool.end();
140
+ });
141
+ ```
142
+
143
+ リファクタリング1号としてはこんな感じになりました。
144
+ ついでにtest関数がPromise.allを直接返すのでasync指定が剥げちゃいましたね…
145
+
146
+ まぁ、関数ってのは値を入れたら結果を返すものなので、
147
+ このようにsql結果を受け取り、`.then`や`.catch`を使って値を調査、poolを閉じた方が設計としては綺麗だと思います。
148
+ 実践は色々また状況が違うので最適なコードも変わってくると思います、頑張ってください!