みーのぺーじ

みーが趣味でやっているPCやソフトウェアについて.Python, Javascript, Processing, Unityなど.

JavaScriptで無限ループの原因を見つける

ブラウザーで実行する JavaScript において,無限ループで処理が進まなくなってしまう不具合が発生した場合に,修正する方法を検討します.

Python など実行を強制終了 (Control+C) できる言語ならば,終了時のスタックトレースを確認することで無限ループの原因はすぐに分かります. JavaScriptの実行を強制終了する機能がブラウザーにないので,次善策となります.

debugger; を挿入する

JavaScriptでは debugger; 文を挿入すると,開発ツールのデバッガが起動して一時停止します.したがって,無限ループする直前と直後の2箇所に debugger; 文を挿入することができれば,ブラウザーで実行し始めると1個目で一時停止し,再開ボタンを押すと応答がなくなる,という挙動になるはずです.範囲を徐々に狭くして,無限ループ内にdebugger; 文を挿入できたら完璧です.

binary search を活用する

binary search (二分探索) *1を活用することで,作業量を減らすことができます.つまり,ソースコードの最初と大体半分ぐらいのところに debugger; 文を挿入して動作を確認します.応答がなくなるかどうかを確認して,原因が挿入したところよりも前か後のどちらにあるかを判定します.これを繰り返していくと効率的に原因を突き止めることができます.

練習

以下のような明らかに無限ループする HTML ファイルを検討してみます.Chrome で実行すると応答しなくなります.

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinite Loop</title>
</head>

<body>
    <div>
        <span id="result"></span>
    </div>
    <script>
        let i = 1;
        const j = i * 2;
        const k = j * 2;
        while (true) {
            i++;
        }
        const t = "k=" + k;
        document.getElementById("result").textContent = t;
    </script>
</body>

</html>

debugger; 文を2個挿入して確認します.

応答があるので,最後の debugger; 文よりも後ろに原因があることが分かりました.場所を変更して確認します.

最後の debugger; 文に移動する前に応答がなくなりましたので,間に原因があることが分かりました.while 文に原因があることが分かりました.

無限ループの中に挿入できれば完璧です.

最後の debugger; 文が次々に実行されていて,無限ループになっていると断定できました.ループ内の情報が取得できるようになったので,修正は簡単です.

まとめ

debugger; 文と binary search による探索方法を検討しました.特別なツールを使わなくても効率的に原因を同定できるので便利だと思います.