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 バージョンのインストール手順と解凍時に発生した問題の概要

推薦する

アイデアを war パッケージにパッケージ化し、tomcat にデプロイしてアクセス パスの問題 (図とテキスト)

Web プロジェクトを war にパッケージ化するアイデアにとって最も重要なことは、アトリフィカを...

Vueは、センシティブな単語フィルタリングコンポーネントを検出するためのさまざまなアイデアを実装しています。

目次前面に書かれた要件分析 v1アイデア1: インターセプションメソッドを使用して入力ボックスの入力...

CSS3はテキストのレリーフ効果、彫刻効果、炎のテキストを実現します

この効果を実現するには、まず CSS のプロパティを知っておく必要があります。 text-shado...

CSS 背景画像を設定するための 6 つの興味深いヒント

background-image は、おそらくすべてのフロントエンド開発者がキャリアの中で少なくとも...

HTML の表のフレームとルール属性の詳細な説明

テーブル タグの frame 属性と rules 属性は境界線の表示を制御できます。フレーム プロパ...

webpackでHMRを手動で実装するいくつかの方法

目次1. はじめに2. GitHub 3. 基本構成プロジェクトディレクトリパッケージ.json c...

MySQL データベース データのロード 複数の用途

目次MySQL Load Dataの多様な用途1. LOAD の基本的な背景2. 基本パラメータをロ...

Docker コンテナのタイムゾーン エラーの問題

目次背景質問問題分析と解決策新たな問題問題分析と解決策背景node-schedule スケジュール ...

子コンポーネントを通じて親コンポーネントのプロパティを変更するための Vue のさまざまな実装方法

目次序文一般的な方法1. 親コンポーネントを介して子コンポーネントの発行イベントをリッスンしてpro...

Linux での i3 ウィンドウ マネージャーの設定と使用に関するチュートリアル

この記事では、Fedora 28 に i3 をインストールして簡単に設定する方法を説明します。 1....

Dockerコンテナのデータボリュームの詳細な説明

何ですかまず、Docker の概念を見てみましょう。アプリケーションと実行環境をコンテナにパッケージ...

知らないかもしれない実用的なTypeScriptのヒント

目次序文関数のオーバーロードマッピングタイプ部分的、読み取り専用、Null 可能、必須選択、記録除外...

jQuery の CSS スタイル属性 css() と width() の完全ガイド

目次1. css() の基本的な使用法: 1.1 CSSプロパティを取得する1.2 CSSプロパティ...

Node.js を使用して C# のデータ テーブル エンティティ クラス生成ツールを作成する方法

Microsoft は T4 テンプレートを提供していますが、使用するのが非常に難しいと思います。ス...

MySQL innodb_autoinc_lock_mode について

innodb_autoinc_lock_mode パラメータは、auto_increment 列を持...