JavaScriptでコールバックな関数をPromise化する
最近のJavaScriptのライブラリはasync/awaitに対応していることが多くなってきました。 おかげで、かなり短かいコードで非同期処理が実現出来るようになっています。
とはいえ、まだまだ非対応のライブラリもあり、混ざってしまった日にはコードが酷いことに…。 というわけで、コールバック関数を渡さないといけない古いスタイルのライブラリを、Promiseでラッピングしてasync/await出来るようにする方法です。
対応前のコード
対応前のコードのイメージは、以下のようなものです。 これを、Promiseを使って綺麗にしていきます。
database.get((data, error) => { if (error) { console.error(error); return; } database.set(data + 1, error => { if (error) { console.error(error); } }); });
データベースから何かの数値を持ってきて、値を加算して格納する、という雰囲気で書いてみたものです。 内容は単純ですが、コールバックが入れ子になってしまって見通しはかなり悪めです…。
Promise化するコード
先ほどのサンプルで使ったdatabase.get
とdatabase.set
をPromiseで包むためには、以下のようなコードを書くことになります。
function getData() { return new Promise((resolve, reject) => { // Promiseのコンストラクタを使って「resolve」と「reject」を作る database.get((data, error) => { if (!error) { resolve(data); // 処理が終わったら、「resolve」に戻り値を渡す } else { reject(error); // 処理に失敗したときは、「reject」にエラーの内容を渡す } }); }); } function setData(data) { return new Promise((resolve, reject) => { database.set(data, error => { if (!error) { resolve(); // 返すべき戻り値が無いのであれば、引数を渡さずに「resolve」を呼び出す } else { reject(error); } }); }); }
対応後のコード
PromiseでラッピングしたgetData
とsetData
を使うと、先ほどの長いコードは以下のように短く書くことが出来るようになります。
getData() .then(data => setData(data + 1)) .catch(error => console.error(error));
async/awaitを使う場合は以下のようになります。こちらの方が直感的ですね。
try { const data = await getData(); await setData(data + 1); } catch(error) { console.error(error); }