【まとめ】JavaScriptのPromiseの扱い方
非同期通信やDB処理の戻り値として使われるPromise型について、少し癖があるので取り扱い方についてまとめておきます。
Promiseとは?
Promiseとは、作成されたときに必ずしも戻ってくる値が分からないものです。使う用途としては、非同期通信やDB処理などが挙げられます。
非同期通信をする際は通信に成功することがほとんどでしょうが、失敗する時もあります。そんな時に成功した場合の処理、失敗した場合の処理を書き分けられるのがPromiseです。
また、DB処理も同じ。DBの接続に失敗したときの処理と成功したときでハンドリング方法を記述できます。
このようにPromiseはスグに値を返すものではなく、将来のある時点で値を返すときに使われます。
Promiseのハンドリング
そして、Promiseから返された値を使う場合はthenメソッド、エラーが返されたときはcatchメソッド、成功時でも失敗時でも処理が動くfinallyメソッドを使ってそれぞれの処理をハンドリングします。
以下のコードでは、DB接続のテストを行っています。
- DB取得成功時(then):「接続成功」を表示
- DB取得成功時(catch):「接続失敗」を表示
- 共通処理(finally):「処理終了」を表示
DB.authenticate()
.then(function() {
console.log("接続成功")
})
.catch(function() {
console.log("接続失敗")
})
.finally(function() {
console.log("処理終了")
})
DB接続成功時
DB接続失敗時
基本的にthen、catch、finallyこの3つのメソッドを使ってpromiseのハンドリングを行います。
thenを繰り返すと可読性が落ちる
しかし、thenを何度も使うとネストが深くなって可読性が落ちがちです。たとえば、以下のコードは会社テーブルから取得したユーザーIDをキーにユーザー名を取得しています。
Company.findByPk(1)
.then(function(value) {
User.findOne({ where: { user_id: value.dataValues.user_id } })
.then(function (value) {
console.log(value.dataValues.user_name);
})
.catch(function() {
console.log("接続失敗")
})
})
.catch(function() {
console.log("接続失敗")
})
.finally(function() {
console.log("処理終了");
})
このようにPromise型の結果から次の処理を行おうとするとthenメソッドが重なり読みづらくなるのです。
可読性のネックを改善するasync/await
「thenを何度も使うと読みづらい」。そんなときに使えるのがasync/awaitです。これを使うことで同期処理のように記述することができます。
先ほどのコードは以下のように書き換えが可能です。
async function writeLog() {
try {
const company = await Company.findByPk(1);
const user = await User.findOne({where : {user_id : company.dataValues.user_id}});
console.log(user.dataValues.user_name)
} catch {
console.log("接続失敗")
} finally {
console.log("処理終了")
}
}
try、catch、finally文を使うことでエラーハンドリング等を行っています。こうすることでthenメソッドで記述する方法よりもスッキリと簡潔に書くことができます。
まとめ
- promiseは成功時、失敗時のハンドリングを記述できる
- thenを何度も使ってくるとネストが深くなり可読性が落ちる
- promiseを何度も使う場合はasync/awaitを使ったほうが読みやすくなる
Discussion