9.4 コールバック関数とコールバック地獄

以前の JavaScript では、非同期処理が終わった後にやりたいことを、引数として渡す小さな関数(コールバック関数)の中に書いていました。

しかし、複数の非同期処理を順番に行おうとすると、関数の中にさらに関数を書くことになり、ネスト(入れ子構造)が深くなることで、コードが非常に読みづらくなってしまいます。

この状態をコールバック地獄や破滅のピラミッドと揶揄していました。

9.4.1 コールバック地獄の例を実行するプログラム

setTimeout 命令を使って、コールバック地獄を実現してみます。

ソースフォルダ:public/ch09

ファイル名:callback-hell.js

➢ callback-hell.html

前の項で作った ch09/delay.html をコピーし、ch09 にペーストしてください。
その際に、ファイル名を callback-hell.html に変更します。
ファイル内の delay.html や delay.js の記述も、callback-hell.html や callback-hell.js に修正します。

➢ callback-hell.js

// callback-hell.js

// 1秒ごとに順番にメッセージを出したい場合
setTimeout(() => {
    alert("1秒経過:ステップ1");

    setTimeout(() => {
        alert("さらに1秒経過:ステップ2");

        setTimeout(() => {
            alert("加えて1秒経過:ステップ3");
            // これ以上続くと、右側へどんどんズレていき、解読不能になります...
        }, 1000);

    }, 1000);

}, 1000);

実行結果

解説

ソースコードの構造とコメントが全てです。
このサンプルプログラムは、メッセージを表示しているだけですが、より複雑な処理をコールバック関数内部に記述した状態で、ネスト(入れ子構造)が深くなると、コードの可読性が落ちることは想像に難くありません。

カッコ { } が何重にも重なり、どこで処理が区切られているのか一目で分からなくなります。これが、多くの開発者を悩ませた「地獄」の正体です。

現代の JavaScript では、この問題を解決するために Promise や async/await という新しい書き方が導入されました。これらについては次章で詳しく学んでいきましょう。