JavaScript Alert関数の実行順序の詳細な説明

JavaScript Alert関数の実行順序の詳細な説明

質問

数日前、JavaScript を使用して HTML ページを作成しているときに奇妙な問題が発生しました。

私が実現したい機能は、ユーザーが confirm() ポップアップ ウィンドウを通じてさまざまな要件を選択できるようにすることです。選択するたびに、選択結果が一時的にページに出力されます。最後の選択後、オプションはバックエンドに渡され、すぐに処理されます。 コードは次のようになります:

var step1 = confirm("step1を実行しますか?");
$('#result').html($('#result').html() + "\n" + ステップ1);
var step2 = confirm("step2を実行しますか?");
$('#result').html($('#result').html() + "\n" + ステップ2);
var step3 = confirm("step3を実行しますか?");
$('#result').html($('#result').html() + "\n" + ステップ3);

送信(ステップ1、ステップ2、ステップ3)

しかし、コードを実行した後、確認関数が実行され、ユーザーがオプションを選択するたびにページが更新されず、ステップ 1 とステップ 2 の結果がリアルタイムでページに更新されず、最後のステップでステップ 3 と一緒に表示されることがわかりました。

次に、confirm に似た 2 つのダイアログ ボックス関数である alert() と prompt() を試しましたが、状況は同じでした。これらはページのレンダリングをスキップし、最初に実行されます。

この時点で、さらに奇妙な状況が発生します。div に値を割り当てると、すぐにこの div 内のコンテンツが警告されます。警告には正しいコンテンツが表示されますが、div 内のコンテンツは更新されず、[OK] をクリックするまでブロックされます。

図に示すように:

アラート、プロンプト、確認の 3 つの機能は似ています。次に、最も単純なアラートを例として使用します。

分析する

この問題を解決する前に、まず何が原因であるかを理解しましょう。それを理解するには、JavaScript スレッド モデルから始める必要があります。

JavaScript エンジンは単一のスレッドで実行されます。ブラウザで JavaScript プログラムを実行するスレッドは常に 1 つだけです。当初の目的は、DOM などの共有リソースの競合を減らすことでした。ただし、単一のスレッドでは常に問題が発生します。つまり、特定のコード セクションをブロックすると、後続のすべてのタスクが遅延します。また、JavaScript はページの DOM を操作して HTTP リクエストを送信する必要があることが多いため、これらの I/O 操作には通常長い時間がかかります。ブロックされると、ユーザーのユーザー エクスペリエンスが非常に悪くなります。

そこで、イベント ループが作成されました。JavaScript は、すべての非同期操作または I/O ブロッキングを伴う操作をイベント キューに入れ、同期 CPU コードを順番に実行し、JavaScript エンジンに同期コードがなく CPU がアイドル状態のときに、イベント キュー内の非同期イベントを読み取って順番に実行します。

これらのイベントには以下が含まれます:

  • setTimeout() によって設定される非同期遅延イベント
  • レイアウトおよび描画イベントに関連する DOM 操作。
  • AJAX リクエスト イベントなどのネットワーク I/O。
  • マウスのクリックやキーボードのストロークなどのユーザー操作イベント。

解決する

原理を理解したので、この問題を解決する方向性がわかりました。この問題を分析してみましょう。

1. ページのレンダリングは DOM 操作であるため、JavaScript エンジンによってイベント キューに配置されます。

2. alert() は window の組み込み関数であり、同期 CPU コードと見なされます。

3. JavaScript エンジンは最初に同期コードを実行し、最初にアラート ポップアップ ウィンドウが表示されます。

4. alert には特別なブロック プロパティがあり、JavaScript エンジンの実行がブロックされます。

5. アラートで「OK」をクリックすると、JavaScript はブロックされなくなり、同期コードの実行後にイベント キュー内の DOM 操作が読み取られ、ページのレンダリングが完了します。

上記の理由により、奇妙な「アラート実行順序の問題」が発生します。 ページのレンダリングを同期操作にすることはできないため、alert() を非同期コードに変換して、ページがレンダリングされた後に実行できるようにする必要があります。

この解決策には 2 つの方法があります。

Alert() 関数を置き換える

まず、アラート機能の機能を置き換えることを検討しましょう。実際、ほとんどの場合、アラートを置き換えるのは、期待する実行順序に準拠していないからではなく、見栄えが悪く、さまざまな美化をサポートしていないからです。特定のテーマの Web サイトに灰色で単調なダイアログ ボックスが突然表示されると、どれほど不調和になるかは想像に難くありません。

Bootstrap のモーダル モジュールを検討することができます。Bootstrap はほとんどの Web サイトで使用されており、もう 1 つのモーダル モジュールを導入しても大きな影響はありません。ポップアップ ダイアログ ボックスを構築するには、モーダルを使用します。モーダルの modal('toggle')/modal('show')/modal('hide') メソッドを使用すると、モーダルの表示を簡単に制御できます。

ダイアログ ボックスを置き換えた後も、後続のコード実行の問題を解決する必要があります。アラート関数を使用する場合、[OK] をクリックした後もコードが引き続き実行されます。ただし、カスタム ダイアログ ボックスを使用する場合、この機能は使用できません。後続のコードをダイアログ ボックスのクリック ボタンにバインドすることを検討する必要があります。これには、DOM のonclick属性を使用する必要があります。後続の関数の内容を新しい関数に抽出し、ダイアログ ボックスがポップアップした後、この関数をボタンの onclick イベントにバインドします。

また、新しい関数にはモーダル ダイアログ ボックスを閉じる内容を含める必要があることにも注意してください。

もちろん、さらに最適化して、アラート機能の代わりにダイアログ ボックスをポップアップする機能を抽象化することもできます。例は次のとおりです。

window.alert = 関数 (メッセージ、コールバック関数) {
    $('#alertContent').html(メッセージ);
    $('#modal').表示();
    $('#confirmButton').onclick(関数() {
        $('#modal').hide();
        コールバック関数();
    });
};

このように、ポップアップ ボックスが必要なときに新しいアラート関数を呼び出し、callbackFunc を渡して、後続の作業を実行します。

setTimeOut関数

もちろん、誰もが新しいダイアログボックスを使用して警告機能ダイアログボックスを置き換えることを望んでいるわけではありません。私は常に上記の方法が特にエレガントではないと感じています。この点では、別の方法を使用してこの問題を解決できます。

フロントエンドを学ぶ学生は、setTimeout() 関数に精通している必要があります。これを使用すると、特定のコードの実行を遅らせることができます。遅延実行コードに関しては、JavaScript エンジンは常にコードをイベント キューに配置し、実行時間が到来したかどうかを確認し、適切なタイミングで実行します。コードがイベント キューに入ると、ページ レンダリング イベントのようにコードが非同期になることを意味します。イベント キューは順序付けられているため、setTimeout を使用して実行を遅延すると、ページがレンダリングされた後にアラート機能を実装できます。

setTimeout の関数プロトタイプは setTimeout(code, msec) です。code は非同期にするコードまたは関数、msec はミリ秒単位の遅延時間です。ここでは遅延する必要はなく、非同期になるだけなので、msec を 0 に設定できます。

同様に、アラートの後のコードも処理し、非同期実行のために setTimeout でアラートと組み合わせる必要があります。こうすると、コードは setTimeout("alert('msg');doSomething();", 0); となります。コードがあまり美しくなかったり、文字列の扱いが難しい場合は、後続のコードを関数にカプセル化して doSomething() 内に入れることもできます。

まとめ

上記の 2 つのソリューションでは、JavaScript コールバック関数が使用されています。前者は関数をアラートのパラメータとして受け取り、DOM の onclick イベントにバインドしますが、後者は setTimeout を使用して関数を非同期実行に変換します。 JavaScript のコールバック関数は確かに非常に強力で使いやすいのですが、コールバックがネストされるという問題が隠れています。単層のコールバックは理解しやすいですが、私のニーズのように、複数のアラートとページ レンダリングが順番に実行されるような状況を実装する場合、「コールバック地獄」に直面する可能性があります。onclick イベント バインディング内の関数は onclick 関数内にネストする必要があり、setTimeout 内に別の setTimeout ステートメントが必要です。問題が発生すると、トラブルシューティングがさらに面倒になります。

上記は、JavaScript Alert関数の実行順序問題についての詳細な説明です。JavaScript Alert関数の実行順序問題についての詳細は、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • アラートポップアップ効果を実現するJavaScript
  • JavaScript の一般的な 3 つのポップアップ プロンプト ボックス (アラート、確認、プロンプト)
  • JavaScript を使用してアラートを実装するためのサンプル コード
  • JavaScript アラートと確認の美化に関する簡単な説明
  • js ファイル内の alert() で表示される中国語の文字が文字化けする問題の解決方法
  • JavaScript SweetAlertプラグインは、非常にクールなメッセージ警告ボックスを実装します
  • JS を使用してアラートに改行を表示する方法
  • JavaScript の alert() 関数の使い方の詳細な説明

<<:  Tomcat メモリ オーバーフロー問題の解決経験

>>:  mysql5.7.24 バージョンのインストール手順と解凍時に発生した問題の概要

推薦する

ラジオボタンとチェックボックス効果の純粋な CSS 実装例

ラジオボタンとチェックボックスラジオボタンとチェックボックスの効果を実現するための純粋な CSSラジ...

Angularの動的コンポーネントの詳細な説明

目次使用シナリオ達成方法1. 動的コンポーネントを配置する場所2. コンポーネントのインスタンスを取...

MySQLのジョイントインデックス機能の分析と使用例

この記事では、例を使用して、MySQL 共同インデックスの機能と使用方法を説明します。ご参考までに、...

カーソル ループを使用して、MySQL ストアド プロシージャで一時テーブルを読み取る

カーソルカーソルは、結果セット内のデータを表示または処理するために使用される方法です。カーソルを使用...

Linux に JDK1.8 をインストールするための詳細なチュートリアル

1. 設置前の清掃 rpm -qa | grep jdk rpm -qa | grep gcj yu...

border-image を使用してテキストバブルの境界線を実装する方法のサンプルコード

開発中に、非常に単純なテキストバブル効果に遭遇しました。これは、おおよそ次のようになります。 うーん...

html リンク タグ タイトル属性 改行 マウス ホバー プロンプト コンテンツ 改行効果

オブジェクト上にマウスを移動したときにコンテンツ(タイトル属性の内容)を折り返す方法、HTML タイ...

Windows 7 での MySQL 8.0.18 の導入とインストールのチュートリアル

1. 事前準備 (windows7+mysql-8.0.18-winx64) 1. ダウンロードアド...

HTMLウェブページの基本概念の簡単な分析

ウェブページとは何ですか? HTML ドキュメントがブラウザカーネルによってレンダリングされた後に表...

VueでTypeScriptを使用する方法

導入近年、TypeScript を求める声がますます高まり、TypeScript はフロントエンドに...

ウェブページのFOUC問題によるウェブページの混乱の解決策

FOUC は Flash of Unstyled Content の略で、FOUC と略されます。簡...

ul リスト タグ デザイン ウェブ ページ 複数列レイアウト

数日前、CSS で 3 列レイアウトを書いていたときに、突然この方法を思いつきました。このアイデアは...

SSHパスワードフリーログイン設定方法の詳しい説明(画像とコマンド)

まず、私たちがやりたいことは、serverA の usera を使用して、パスワードなしで serv...

CSS floatプロパティの詳細な説明

1. フローティングとは何ですか?フローティングは、その名の通り、浮遊することを意味します。要素がド...

モバイルインターネット時代: レスポンシブウェブデザインが一般的なトレンドに

今はモバイルインターネットが急速に発展している時代です。スマートフォンやタブレットはますます普及し、...