はじめに
今までJavaScriptでaws-sdkを扱う場合は
↓こんな感じでコールバック関数を渡していました。
もともと
s3.listBuckets((err, data) => {
if (err) {
console.error(err);
} else {
console.log(data);
}
});
簡単な処理の場合はこの書き方で良いと思うのですが
処理を手続き的に書く際にとても苦労します・・・
いわゆるコールバック地獄
dynamoDB.getItem({/*省略*/}, (err, data) => {
if (err) {
console.error(err); // エラーもネストの数だけハンドリングが必要
} else {
s3.getObject({/*省略*/}, (err, data) => {
if (err) {
console.error(err);
} else {
console.log(data);
}
});
}
});
これを回避するためにasync/awaitを使おうとすると
すべてのApi呼び出しをPromiseでラップする関数を定義する必要がありました。
ラップした例
// これはこれでコールバック地獄
// しかも使用するApiの数だけ用意する・・・
function getItem(opts) {
return new Promise((resolve, reject) => {
dynamoDB.getItem(opts, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
// メイン処理
// ここはきれいに書ける
async function hoge() {
try {
const res1 = await getItem({/*省略*/});
const res2 = await getObject({/*省略*/});
console.log(res2);
} catch(err) {
console.error(err); // エラーもまとめてハンドリングできる
}
}
これを回避するためにオレオレPromisifyなども作ったりしました。
コールバック地獄にも終わりが!
最近だと↓こう記述できるとのこと
今どき
async function hoge() {
try {
const res1 = await dynamoDB.getItem({/*省略*/}).promise();
const res2 = await s3.getObject({/*省略*/}).promise();
console.log(res2);
} catch(err) {
console.error(err);
}
}
見ての通りApi呼び出し後の戻り値から
そのままPromiseが返却できるらしいのです。
このpromise()
関数はAWS.Request
の実装なので
例に限らずほぼ全てのAPIで使用可能だと思われます。(※ 確認したわけではありません)
まとめ
調べてみると2016年のLambdaがNode.v4対応した頃には実装されていたようですが、
公式のサンプルもコールバックを渡すプログラムになってたりするので
このpromiseの存在を知らない人もまだいるのではないでしょうか?(まさか僕だけ・・・?
ぜひPromiseを使ってシンプルな非同期処理を書いてきましょう!
参考記事
追加
気がつくと公式にページが追加されてたのでリンクしておきます