Global Trend Radar
Web: qiita.com US web_search 2026-05-05 18:42

レガシーなcallbackをasync/awaitで書き直す #JavaScript - Qiita

元記事を開く →

分析結果

カテゴリ
AI
重要度
60
トレンドスコア
24
要約
レガシーなcallbackをasync/awaitで書き直す #JavaScript - Qiita 6 いいねしたユーザー一覧へ移動 6 X(Twitter)でシェアする Facebookでシェアする はてなブックマークに追加する more_horiz 記事を削除する close 一度削除した記事は復旧できません。 この記事の編集中の下書きも削除されます。 削除してよろしいですか? キャンセル 削除する delete info この記
キーワード
レガシーなcallbackをasync/awaitで書き直す #JavaScript - Qiita 6 いいねしたユーザー一覧へ移動 6 X(Twitter)でシェアする Facebookでシェアする はてなブックマークに追加する more_horiz 記事を削除する close 一度削除した記事は復旧できません。 この記事の編集中の下書きも削除されます。 削除してよろしいですか? キャンセル 削除する delete info この記事は最終更新日から3年以上が経過しています。 @ Esperna ( Esperna Shrimp ) レガシーなcallbackをasync/awaitで書き直す JavaScript Node.js callback promise async 6 最終更新日 2023年05月05日 投稿日 2023年04月30日 こんにちは。 @Esperna です。 @asip2k25 さんのコメントでresolveしたものに対してわざわざ配列で個別に代入しなくて良いことに気づきました。ありがとうございます。 背景 callbackを使ったコードって読めなくはないのですが、callback処理の内容を覚えておかなければならず、読みづらいです。また、ネストも深くなりがち。読みにくいのでPromiseとかasync/await使って直したいなと思うことがあります。Promiseとかasync/awaitは JavascriptPrimer を読んで、実際のcallbackのコードを書き直そうと思うとデグレが怖く二の足を踏んでしまいがち。最近はGPTの使いこなしネタが多く、そちらに追従して効率上げることも大事だなと思う一方、ちゃんと分かって書けることは大事だと思って、車輪の再発明ながら自身の理解を深めるために書きます。 というわけで、Javascriptのcallback処理をPromise, async/awaitで書き直してみようと思います。 callbackのコード例 callback.js function asyncTask ( callback ) { const TIMEOUT = 10 ; setTimeout (() => { var data = 0 ; if ( Math . random () > 0.5 ) { data = 1 ; callback ( null , data ); } else { callback ( new Error ( " Invalid Data " ), data ); } }, TIMEOUT ); } asyncTask (( err , data ) => { if ( err === null ) { console . log ( `successfully finished task. Data: ${ data } ` ); } else { console . error ( `error occured: ${ err } : ${ data } ` ); } }); console . log ( " called asyncTask " ); これは非同期処理であるasyncTaskを実行するコードです。 asyncTaskはcallbackを引数に取ります。 引数には無名関数(アロー関数)を渡していて、 この無名関数はエラーがない場合 called asyncTask successfully finished task. Data: 1 というコンソールログが表示されます。 エラーがある場合は called asyncTask error occured: Error: Invalid Data: 0 というコンソールログが表示されます。 一方、asyncTaskという関数は内部でsetTimeoutをコールすることで、 非同期処理を行うようにしていて、エラーがない場合とある場合を実現するのに Math.random()を使ってランダムにそれぞれのケースを発生させてます。 Promiseを使ってcallbackを書き直す 下記の通りです。 promise.js function asyncTask () { return new Promise (( resolve ) => { const TIMEOUT = 10 ; setTimeout (() => { var err = null ; var data = 0 ; if ( Math . random () > 0.5 ) { data = 1 ; } else { err = new Error ( `Invalid Data: ${ data } ` ); } resolve ({ err , data }); }, TIMEOUT ); }); } asyncTask (). then (( res ) => { if ( res . err === null ) { console . log ( `successfully finished task. Data: ${ res . data } ` ); } else { console . error ( `error occured: ${ res . err } ` ); } }); console . log ( " called asyncTask " ); callback版との違いを見てみると Promise版の方が以下の理由でコードが長くなっています asyncTaskがPromiseを返すようにする必要がある Javascriptで複数の戻り値(err,data)を返すのに配列を使っている resolveで略記プロパティ名 (ES2015)を使っています callbackの呼び出しがなくなっています 元のコードのcallbackのネストが浅いから効果が見えにくい async/awaitを使ってみる async_await.js function asyncTask () { return new Promise (( resolve ) => { const TIMEOUT = 10 ; setTimeout (() => { var err = null ; var data = 0 ; if ( Math . random () > 0.5 ) { data = 1 ; } else { err = new Error ( `Invalid Data: ${ data } ` ); } resolve ({ err , data }); }, TIMEOUT ); }); } async function doAsyncTask () { const { err , data } = await asyncTask (); if ( err === null ) { console . log ( `successfully finished task. Data: ${ data } ` ); } else { console . error ( `error occured: ${ err } ` ); } } doAsyncTask (); console . log ( " called asyncTask " ); Promise版との違いは asyncTask.then()という書き方をasync/awaitという書き方に置き換えられスッキリしました 一方でasync/awaitの形にするために無名関数ではなくdoAsyncTaskというasync functionを追加しているので少しコード行数は増えています err,dataに値を入れるのに分割代入を使っています Promiseでresolveだけでなくrejectも使ってみる async_await2.js function asyncTask () { return new Promise (( resolve , reject ) => { const TIMEOUT = 10 ; setTimeout (() => { var data = 0 ; if ( Math . random () > 0.5 ) { data = 1 ; resolve ( data ); } else { reject ( new Error ( `Invalid Data: ${ data } ` )); } }, TIMEOUT ); }); } async function doAsyncTask () { try { const data = await asyncTask (); console . log ( `successfully finished task. Data: ${ data } ` ); } catch ( err ) { console . error ( `error occured: ${ err } ` ); } } doAsyncTask (); console . log ( " called asyncTask " ); Promise版、async/await版を比べると配列で返って来た戻り値を再代入することがなくなったのでシンプルになりました 個人的には err, data = await asyncTask(); と書けると嬉しいのだが、javascriptでは配列にしないと書けないという認識 Promise版、async/await版を比べるとerr,dataを引数で受け取るのではなく、関数内部でasyncTask()の戻り値で受け取るので結合度の観点では悪くなってますね callback版と比べると 正常系のcallbackがresolveに、異常系のcallbackがrejectに置き換わってます asyncTaskの引数で渡される無名関数がasync function doAsyncTaskとなっています asyncTask関数内のif/elseがasync function doAsyncTask内のtry/catchに置き換わってます 所感 callbackのネストが浅いとcallbackをasync/awaitにしてもコードの可読性が良くなったように見えにくい async/awaitによりcallbackがなくなり、callback処理を覚えておく必要がなくなるので読みやすくなる テストコードも書きやすくなる resolve,rejectを使うとコード行数もそこまで変わらずスッキリ書けて読みやすい callbackをasync/awaitに書き直そうと思ったら、callbackで渡す関数をasync functionにしつつ、callbackを受け取る非同期関数をasync function内でawaitしてあげればOK 6 いいねしたユーザー一覧へ移動 6 comment 7 コメント一覧へ移動 新規登録して、もっと便利にQiitaを使ってみよう あなたにマッチした記事をお届けします 便利な情報をあとで効率的に読み返せます ダークテーマを利用できます ログインすると使える機能について 新規登録 ログイン 6 いいねしたユーザー一覧へ移動 6 more_horiz 記事を削除する close 一度削除した記事は復旧できません。 この記事の編集中の下書きも削除されます。 削除してよろしいですか? キャンセル 削除する delete

類似記事(ベクトル近傍)