JavaScript Alert関数の実行順序の問題を詳しく説明します。


問題
先日はJavaScriptを使ってHTMLページを書いていましたが、変な問題がありました。
私が実現したい機能はconfirm()の弾戸を通してユーザーに異なる需要を選択させ、毎回選択したら選択結果を一時的にページに出力し、最後の選択が終わったらもう一度選択して後端に処理します。コードは以下の通りです

var step1 = confirm("exec step1?");
$('#result').html($('#result').html() + "
" + step1); var step2 = confirm("exec step2?"); $('#result').html($('#result').html() + "
" + step2); var step3 = confirm("exec step3?"); $('#result').html($('#result').html() + "
" + step3); send(step1, step2, step3);
しかし、コードを実行した後、毎回confirm関数を実行し、ユーザーがオプションを選択した後、ページは更新されませんでした。Step 1、Step 2の結果はリアルタイムでページに更新されませんでした。最後のステップまでStep 3と一緒に表示されました。
その後、alert()とprompt()という2つのconfirmと似たような弾き語りダイアログ関数を試しましたが、いずれもこれと同じように、ページレンダリングをスキップして先に実行されます。
この時、もっと怪しい状況があります。私達はあるdivに値を付けた後、直ちにalertこのdivの内容はalertが正しい内容を表示していることを発見します。divの内容は更新されていません。そしてずっとブロックされて私達がクリックして確定します。
図のように:

alert、prompt、confirmの三つの関数は似ています。次に簡単なalertで話します。
分析
この問題を解決する前に、JavaScriptのスレッドモデルから説明する必要があります。
JavaScriptエンジンは単一スレッドで実行されています。ブラウザはいつでもJavaScriptプログラムを実行しています。DOMなどの共有リソースの衝突を減らすためです。しかし、スレッドは常に問題に直面しています。つまり、コードのブロックが後続のすべてのタスクを遅延させます。また、JavaScriptは、頻繁に操作ページDOMとHTTP要求を送信する必要があるので、これらのI/Oの操作は、一般的には長い時間がかかり、ブロックされると、ユーザーに非常に悪い使用体験を与えます。
イベントサイクルの発生により、JavaScriptは、例外的な操作やI/Oブロッキングのある操作をすべて一つのイベントキューに置いて、まず同期CPUコードを順次実行し、JavaScriptエンジンが同期コードを持っていないときは、CPUが暇になったらイベントキューの非同期イベントを読み出して順次実行する。
これらのイベントは以下を含む。
  • setTimeout()に設定された非同期遅延イベント。
  • DOM動作は、レイアウトおよび描画イベントのような相関がある。
  • ネットワークI/OはAJAX要求イベントのようです。
  • ユーザは、マウスクリックやキーボードのようなイベントを操作します。
  • 解決
    原理が分かりました。この問題を解決する方向があります。この問題を分析します。
    1.ページレンダリングはDOM操作なので、JavaScriptエンジンにイベントキューに入れられます。
    2.alert()はwindowの内蔵関数であり、同期CPUコードと見なされる。
    3.JavaScriptエンジンは優先的に同期コードを実行します。alert弾戸は先に現れます。
    4.alertは特殊な渋滞性質があり、JavaScriptエンジンの実行がブロックされています。
    5.alertの「確定」をクリックして、JavaScriptはブロックされていません。同期コードを実行した後、またイベントキューのDOM操作を読み込み、ページのレンダリングが完了しました。
    上記の原因により、怪しい「Alert実行手順問題」が発生しました。私たちはページのレンダリングを同期操作に変えることができません。alert()を非同期コードに変えてこそ、ページレンダリング後に実行できます。
    この解決の方向については、2つの方法があります。
    代替Alert()関数
    まずalert関数を置き換える機能を考えます。多くの場合、私たちがalertを交替するのは期待通りの実行順序ではないです。それは本当に醜すぎて、美化も支持していません。ある特定のテーマのウェブサイトで突然一つの灰色の単調な対話枠が弾いてくると想像できます。
    これはBootstrapのmodalモジュールを考えることができます。Bootstrapはほとんどのウェブサイトで応用されていますが、modalモジュールを多く導入してもあまり影響がありません。私たちはmodalを使ってダイアログが飛び出すように構成しています。modalのmodal('toggale')/modal('show')/modal('hide')を使ってmodalの表示を簡単にコントロールできます。
    ダイアログを交換した後、後続コードの実行問題を解決する必要があります。alert関数を使う時、私達はクリックして決定した後もコードは実行されますが、私達がカスタマイズしたダイアログを使ってこの機能がないかもしれません。後続のコードをダイアログのクリックボタンに結びつける必要があります。これはDOMのonclick属性を使う必要があります。後の関数の内容を新しい関数を抽出します。この関数は、ポップアップダイアログの後にボタンのOclickイベントに結び付けられます。
    なお、新しい関数にはmodalダイアログを閉じる内容が含まれるべきである。
    もちろん、私達は更に最適化してもいいです。抽象的に一つのダイアログをイジェクトするための関数がalert関数の代わりになります。例は以下の通りです。
    
    window.alert = function (message, callbackFunc) {
        $('#alertContent').html(message);
        $('#modal').show();
        $('#confirmButton').onclick(function () {
            $('#modal').hide();
            callbackFunc();
        });
    };
    このように、私達は枠をはじく必要がある時に新しいalert関数を呼び出して、calbackFncに入ってきて、中で後のことをすればいいです。
    set TimeOut関数
    もちろん、すべての人が新しいダイアログを使ってalert関数を交替したいというわけではありません。上記の方法は特に優雅ではないように感じられます。これに対して、別の方法で解決します。
    フロントエンドの学生はsetTimeout()という関数に不慣れではないはずです。これを使って、一部のコードを遅延して実行することができます。そして、遅延実行のコードに対しては、JavaScriptエンジンは常にこれらのコードをイベントキューに入れて、実行時間になったかどうかを確認してから実行します。コードがイベントキューに入ると、コードがページレンダリングイベントと同じ非同期になることを意味します。イベントキューが整然としているので、setTimeout遅延で実行すれば、ページレンダリング後にalertの機能を実行することができます。
    setTimeoutの関数のプロトタイプはsetTimeoutで、codeは非同期になるコードまたは関数であり、msecは遅延する時間であり、単位はミリ秒である。ここでは延長は必要ありません。非同期にすればいいです。msecを0に設定できます。
    同様に、alert以降のコードも処理しなければなりません。それらをsetTimeoutに置いて非同期的に実行します。このようにコードはsetTimeout("alert('msg')になります。doSomething()""0)コードが美しくない、または文字列がよくないと感じたら、後続コードを関数としてdoSomething()に入れてもいいです。
    結び目
    上記の2つの解では、JavaScriptのコールバック関数を利用して、前者は関数がalertであるパラメータをDOMのonclickイベントに結びつけ、後者はsetTimeoutを使用して関数を非同期に変えて実行する。JavaScriptのコールバック関数は確かに非常に強力で、使用も簡単ですが、一つの問題があります。つまり、ネストの問題です。単層のコールバックは分かりやすいです。しかし、もし私のニーズのように複数のalertとページが交互に実行されている場合、直面する可能性があります。onclickイベントバインディングの関数はまたバインディングonclick関数をネスティングします。setTimeoutにはもう一つのsetTimeout文が必要です。問題が発生すると、検査が面倒になります。
    以上はJavaScript Alert関数の実行順序に関する詳細な内容です。JavaScript Alert関数の実行順序についての詳細は他の関連記事に注目してください。