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

推薦する

MySQL の undo、redo、binlog の違いを簡単に分析します

目次序文【ログ取り消し】 【REDOログ】 【バイナリログ】要約する序文MySQL には、REDO ...

よく理解しましたかタグ 定義方法 使用方法

序文:今日、「<!DOCTYPE> タグを注意深く理解しましたか?」と尋ねられました。私...

Vueのフロントエンドシステムとフロントエンドとバックエンドの分離の詳細な説明

目次概要フロントエンド知識システムフロントエンドの3つの要素プレゼンテーション層 (CSS)動作レイ...

JS で列挙をシミュレートする方法

序文現在の JavaScript には列挙の概念がありません。一部のシナリオでは、列挙を使用するとデ...

Win10 64ビットMySQL8.0のダウンロードとインストールのチュートリアル図

公式サイトから MySQL をダウンロードしてインストールし、クライアントにログインするにはどうすれ...

VueでTypescriptの設定手順を使用する

目次1. TypeScriptが古いVueプロジェクトに導入されるVue+Typescript プロ...

MySQLパスワード変更例の詳細な説明

MySQLパスワード変更例の詳細な説明長い間 MySQL を使用していませんでした。今日、MySQL...

Linux コマンドラインで他のユーザーと通信する方法

Linux のコマンドラインで他のユーザーにメッセージを送信するのは簡単です。これを行うコマンドは多...

MySQL の隠し列の詳細表示

目次1. 主キーが存在する2. 主キーはないが、一意のインデックスが存在する3. 共同主キーまたは共...

Vueフィルターとカスタム命令の使用

目次フィルター01.とは02. やり方(1)フィルターを定義する(2)使用方法(3)フィルタパラメー...

HTML におけるいくつかの特殊属性タグの使用法の紹介

以下の属性はブラウザとの互換性があまりありません。 1.transform:rotate(45度) ...

デザイナーの「職業病」について

デザイナーは世界で最も繊細で感情的な人々だと私はいつも感じています。私がこう言うときに優越感を感じる...

MYSQLパターンマッチングREGEXPの使用に関する一般的な話など

のようにLIKE ではデータ全体が一致する必要がありますが、REGEXP では部分的な一致のみが必要...

Vue における LocalStorage と SessionStorage の違いと使い方

目次LocalStorageとはSessionStorageとはLocalStorage と Ses...