「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > コールバック地獄を理解する: 問題、解決策、コード例

コールバック地獄を理解する: 問題、解決策、コード例

2024 年 11 月 8 日に公開
ブラウズ:173

Understanding Callback Hell: The Problem, Solutions and Code Examples

コールバック地獄は、開発者の非同期コードの理解と、読みやすさと保守性を向上させるためにコードをリファクタリングする能力をテストするため、技術面接でも注目のトピックです

導入

非同期プログラミングは、最新の JavaScript 開発において非常に重要であり、ノンブロッキングの実行を可能にし、特に I/O バウンドの操作のパフォーマンスを向上させます。ただし、この利便性により、「コールバック地獄」

として悪名高い状態が発生することがあります。

この記事では、次の内容について詳しく説明します:

  1. コールバック地獄とは何か、そしてそれはどのように起こるのか。
  2. それが引き起こす問題。
  3. Promise や async/await の使用を含むソリューション。
  4. すべてを明確にするためのコード例。

コールバック地獄とは何ですか?

コールバック地獄は、「破滅のピラミッド」とも呼ばれ、複数のネストされた非同期操作が相互に依存して順番に実行されるときに発生します。このシナリオでは、深くネストされたコールバックが複雑に絡み合い、コードの読み取り、保守、デバッグが困難になります。

コールバック地獄の例:

getData(function(data) {
  processData(data, function(processedData) {
    saveData(processedData, function(response) {
      sendNotification(response, function(notificationResult) {
        console.log("All done!");
      });
    });
  });
});

上記のコードは、いくつかの非同期操作を順番に実行します。それは機能しますが、タスクが追加されるとすぐに管理できなくなり、理解と維持が困難になります。入れ子の構造がピラミッドに似ているため、「破滅のピラミッド」という用語が付けられました。

コールバック地獄の問題

コールバック地獄はいくつかの問題を引き起こします:

  1. 保守が難しい: 深くネストされたコードは変更/拡張が困難です。新しい機能を追加しようとするだけでバグが発生する可能性があります。
  2. エラー処理: さまざまなネストされたレイヤーにわたる適切なエラー処理は複雑になります。個々のコールバックごとにエラーを処理する必要があるため、コードが繰り返される可能性があります。
  3. コードの読みやすさ: 実行フローを理解することは、特にコードベースに慣れていない開発者にとっては困難になります。
  4. スケーラビリティ: ネストされたコールバックの数が増えると、複雑さも増し、コ​​ードがスケーラブルでなくなり、デバッグが困難になります。

約束: コールバック地獄の解決策

コールバック地獄の問題を軽減するために、JavaScript では Promises が使用されます。 Promise は非同期操作の最終的な完了 (または失敗) を表し、クリーンで管理しやすいコードを作成できるようにします。 Promises によるコードの簡素化 - Promises を使用すると、ネストされた構造が平坦化され、エラー処理がより集中化され、コードが読みやすく、保守しやすくなります。

Promises を使用した前述のコールバック地獄の例は次のとおりです:

getData()
 .then(data => processData(data))
 .then(processedData => saveData(processedData))
 .then(response => sendNotification(response))
 .then(notificationResult => {
 console.log("All done!");
 })
 .catch(error => {
 console.error("An error occurred:", error);
 });

このアプローチにより、深くネストされたコールバックが排除されます。各「then」ブロックはチェーンの次のステップを表し、フローがより直線的になり、追跡しやすくなります。エラー処理も「catch」ブロックに集中されます。

Promise の仕組み

Promise には 3 つの状態が考えられます:

  1. 保留中: 初期状態。約束がまだ履行されていないか、拒否されていないことを意味します。
  2. Fulfilled: 非同期操作は正常に完了しました。
  3. 拒否されました: 操作は失敗しました。

Promise オブジェクトは、成功シナリオと失敗シナリオを処理するための '.then()' メソッドと '.catch()' メソッドを提供します。

function getData() {
 return new Promise((resolve, reject) => {
 // Simulating an async operation (e.g., API call)
 setTimeout(() => {
 const data = "Sample Data";
 resolve(data);
 }, 1000);
 });
}
getData()
 .then(data => {
 console.log("Data received:", data);
 })
 .catch(error => {
 console.error("Error fetching data:", error);
 });

上記のコードでは、「getData()」関数は Promise を返します。非同期操作が成功すると、Promise はデータで履行されます。そうでない場合は、エラーで拒否されます。

約束を連鎖させる

Promise の大きな利点の 1 つは、Promise をチェーンできることです。これにより、ネストせずに非同期操作をシーケンスすることができます。

function fetchData() {
 return new Promise((resolve, reject) => {
 setTimeout(() => resolve("Data fetched"), 1000);
 });
}
function processData(data) {
 return new Promise((resolve, reject) => {
 setTimeout(() => resolve(`${data} and processed`), 1000);
 });
}
function saveData(data) {
 return new Promise((resolve, reject) => {
 setTimeout(() => resolve(`${data} and saved`), 1000);
 });
}
fetchData()
 .then(data => processData(data))
 .then(processedData => saveData(processedData))
 .then(result => {
 console.log(result); 
// Output => Data fetched and processed and saved
 })
 .catch(error => console.error("Error:", error));

Promise を連鎖させることで、コードがフラットになり、読みやすくなり、保守が容易になります。

Async/Await: さらに優れた代替手段

Promise はコールバックに比べて大幅に改善されていますが、大規模なチェーンでは依然として煩雑になる可能性があります。ここで async/await が登場します。
Async/await 構文を使用すると、同期コードに似た方法で非同期コードを作成できます。これにより、コードがよりクリーンになり、推論が容易になります。

非同期/待機の使用:

async function performOperations() {
  try {
    const data = await getData();
    const processedData = await processData(data);
    const response = await saveData(processedData);
    const notificationResult = await sendNotification(response);

    console.log("All done!");
  } catch (error) {
    console.error("Error:", error);
  }
}

performOperations();

上記のコード内:

  • 「async」キーワードは、非同期関数を定義するために使用されます。
  • 'await' は、Promise が解決されるか拒否されるまで関数の実行を一時停止し、コードが同期的に見えるようにします。
  • 単一の 'try-catch' ブロックを使用することで、エラー処理がはるかに簡単になります。
  • Async/await はコールバック地獄と長い約束チェーンを排除し、最新の JavaScript で非同期操作を処理するための推奨される方法になります。

結論

コールバック地獄 は、複数の非同期操作を操作するときに発生する JavaScript の一般的な問題です。コールバックが深くネストされていると、コードが保守不能になり、エラーが発生しやすくなります。ただし、Promises と async/await の導入により、開発者はよりクリーンで管理しやすく、スケーラブルなコードを作成できるようになりました。

Promises はネストされたコールバックを平坦化し、エラー処理を一元化します。一方、async/await は非同期ロジックを同期的に見せることでさらに簡素化します。どちらの手法もコールバック地獄の混乱を排除し、複雑さが増してもコードが読みやすい状態を維持できるようにします。

ソーシャルメディアハンドル
この記事が役立つと思われた場合は、より詳しい情報を得るために、私のソーシャル メディア チャネルでお気軽にご連絡ください:

  • GitHub: [AmanjotSingh0908]
  • LinkedIn: [アマンジョット シン サイニ]
  • Twitter: [@AmanjotSingh]

読んでいただきありがとうございます!

リリースステートメント この記事は次の場所に転載されています: https://dev.to/amanjotsingh/ Understanding-callback-hell-the-problem-solutions-and-code-examples-3loh?1 侵害がある場合は、[email protected] までご連絡ください。それを削除するには
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3