2

今日Firefoxでクライアント側のJavaScriptをデバッグしているときに、かなり奇妙で少し不安なことに遭遇しました。また、IE / VS2010で同じスクリプトをデバッグしているときに、この動作を再現できませんでした。

私が見ている異常を説明するために、簡単なサンプルhtmlドキュメントを作成しました。

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js" type="text/javascript" ></script>
</head>

<body id="main_body">
    <script type="text/javascript">
        $(function () {
            $(".test-trigger").on("click", function () {
                loadStuff();
                console && console.log && console.log("this will probably happen first.");
            });
        });

        function loadStuff() {
            $.get("http://google.com/")
                .fail(function () {
                    console && console.log && console.log("this will probably happen second.");
                });
            }
    </script>
    <button class="test-trigger">test</button>
</body>
</html>

このドキュメントをFirefoxにロードし(Windows 7のFirebugバージョン1.10.1でバージョン13.0を使用しています)、[テスト]をクリックし、Firebugのコンソールタブを表示すると、getリクエストが失敗することに気付くはずです(クロスドメイン違反は何もありません私がここで作ろうとしているポイントを使ってください)、そうすれば、おそらく次のようになります:

this will probably happen first.
this will probably happen second.

次に、13行目と20行目にブレークポイントを設定します。

13: console && console.log && console.log("this will probably happen first.");
20: console && console.log && console.log("this will probably happen second.");

もう一度[テスト]をクリックすると、期待どおりに13行目で中断します。ここで、実行を再開します。あなたの経験が私のようなものであれば、20行目で中断することはありません。また、コンソールタブに切り替えると、次の一連のログ出力が表示されます。

this will probably happen second.
this will probably happen first.

私にとって、これはajaxリクエストの失敗ハンドラーがクリックハンドラーが実行されているスレッド以外のスレッドで実行されていることを示唆しています。私は常に、単一ページのすべてのJavaScriptがによって実行されると信じるように導かれてきました任意のブラウザの単一スレッド。私はここで本当に明白な何かを逃していますか?この観察についての洞察に感謝します。

ああ、Visual Studioを使用してIEで実行されている同じページをデバッグすると、予想どおりに両方のブレークポイントがヒットします。

4

3 に答える 3

2

観察している異常は、Firebugが内部でブレークポイント/動作を実装する方法が原因であると考えるのが安全だと思います。でも確認できません。これは、OSXのFF14でも発生します。

jQueryがすぐに関数を実行し、オブジェクトfail()全体を超えない限り、ステートメントの順序は。になるという保証があります。XMLHttpRequestthis will probably happen first.this will probably happen second.

JavaScriptのシングルスレッドの性質を考えると、関数は本質的にアトミックです。コールバックによって中断されることはありません。

clickを呼び出した後、関数の実行が完了するまでに時間がかかる場合に何が起こるかをシミュレートしようとしているようですloadStuff()click関数は、実行中のメソッドによって中断されるべきではありませんfail(それを実現する方法を見つけたことを気に留めてください)。

方程式からブレークポイントを取り除くために、これが修正されたバージョンです。残りのマークアップは変更されていません。

$(function () {
    $(".test-trigger").on("click", function () {
        loadStuff();
        for (var i = 0; i < 1000000000; i++)
        {
            //block for some interesting calculation or something
        }
        console && console.log && console.log("this will probably happen first.");
    });
});

function loadStuff() {
    $.get("http://google.com/")
        .fail(function () {
            console && console.log && console.log("this will probably happen second.");
        });
    }

を呼び出した後、関数のclick実行には明らかに長い時間がかかりますloadStuff()が、コンソールはここでログステートメントの正しい順序を反映します。また、同じブレークポイントを挿入すると、元の例のように順序が無効になることにも注意してください。

これについてはFirebugに問題を報告します。

于 2012-08-03T21:37:54.260 に答える
0

$.get("http://google.com/")非同期であり、最初に行われることの競争です。呼び出しを行う必要があり、呼び出しはコード実行の後半で発生するため、最初は遅くなります。呼び出しは2番目の要求ですでにキャッシュされているため、たまたま実行速度が速くなります。

リクエストが送信される前に何かを行う必要がある場合は、beforeSend()を使用してください。

于 2012-08-03T20:35:03.877 に答える
0

私の経験では、非同期コードにブレークポイントを設定すると、Firebugはうまく機能しません。

つまり、実行の直線が1つあり、その中にブレークポイントを設定すれば、問題はありません。ただし、たとえばを使用して非同期性を導入した場合setTimeout、その「並列」行のブレークポイントに到達することはありません(もちろん、実際には並列ではありません。JSエンジンはタスクを切り替えます)。私はここ数ヶ月でそれをたくさん経験しています。

Chromeでは、正常に機能しているようです(タイムアウトをインテリジェントに延期します)。おそらく、Chrome開発ツールがブラウザに組み込まれているため、タイムアウトを操作する方が簡単です。Firebugは「単なる」アドオンであり、正しく実行するのは難しいかもしれません。

問題を再現するための簡単なスクリプト:

x、、yに値を割り当てるときは、行にブレークポイントを設定しますz。まず、行のブレークポイントに到達しますx = 1F10ステップオーバーするために使用します。(Firefox 14、Firebug 1.10)を押すのに十分な速さがある場合にのみ、行のブレークポイントにヒットすることはありませんz = 3z = 3F10

<!DOCTYPE html>
<html>
<body>

<script type="text/javascript">
function foo(){
   var x = 1;
   setTimeout(bar, 2000);
   var y = 2;
}

function bar(){
   var z = 3;
}

foo();
</script>

</body>
</html>
于 2012-08-06T19:46:28.283 に答える