callbackの関数をawait化する
この記事はJavaScriptカレンダー2021 1日目の記事です。過疎っているので1日目getしちゃいました。
Github: https://github.com/bluepost59/callback_to_await
Promise
Promiseとはcallbackを回避するために実装されている機能です。Promiseオブジェクトは言葉にするのが難しいのですが、日本語にすると「お約束」という意味です。「この処理が終わったら次はこうする」というようなお約束を作っておくことで、非同期処理を見通しよく書けるようになります。
const mypromise = new Promise(
(resolve, reject) => {
if (err) reject(err);
resolve()
}
);
Promiseを使うときは、まずコンストラクタにresolve
とreject
を引数に持つ関数を与えてPromiseオブジェクトを作ります。この2つはともに関数で仮引数のようなもので、resolve
には処理が問題なく終了したときに実行される処理、reject
にはエラーが生じたときの処理を代表させます。
本題で詳しく説明しますが、await
句をつけることでPromiseを解決することができます。これによってcallback地獄に陥ることなく逐次処理に近い形で記述できます。
Promiseでcallbackをawaitで見通しよく書く
ここからが本題です。既存の関数でcallbackを使う仕様になっているものをうまくラップして、awaitで処理できるようにします。
今回は簡単のためにsetTimeoutをawaitで逐次実行のように記述できるようにします。
// 1秒経ったら"finished"と表示する
setTimeout(() => {
console.log("finished");
}, 1000);
引数や戻り値が不要な場合
引数や戻り値が不要な場合は、次のようにPromiseで包むことでそのままawaitで実行できるようになります。
const timeout_promise = new Promise(
(resolve, reject) => {
setTimeout(resolve, 1000);
}
);
// 実行パート
// Promiseなので()をつけない
async function main(){
await timeout_promise;
console.log("finished");
}
awaitはasync function内でしか使うことができません。これはトップレベルも含んでいて、ベタにawaitを使おうとするとエラーが出るので注意しましょう。
引数や戻り値を取る場合
一番実践的なパターンかと思います。引数や戻り値を取る場合、builderとなる関数を用意してPromiseを返すようにします。
function timeout_function(msg) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(msg);
}, 1000);
});
}
// 実行パート
async function main(){
// awaitで逐次実行のように記述できる
res = await timeout_function("finished");
console.log(res);
}
まとめ
JavaScriptのPromiseという仕様は他の言語がメインの人にはわかりにくいと思います。自分もまとめるまでよくわかっていませんでした。ただ使い方を覚えればcallbackと段違いにわかりやすいコードを書くことができるので、積極的に使っていきましょう。
Discussion