ホームページ  >  記事  >  ウェブフロントエンド  >  技術的な回答: JavaScript 実行メカニズム

技術的な回答: JavaScript 実行メカニズム

WBOY
WBOY転載
2022-01-14 17:23:171326ブラウズ

この記事では、JavaScript の実行メカニズムに関する問題をいくつか紹介します。仕事でも面接でも、コードの実行順序を知りたい場面によく遭遇します。皆さんのお役に立てれば幸いです。 。

技術的な回答: JavaScript 実行メカニズム

プロセスとスレッド

コンピュータの中核はCPU はすべてのコンピューティング タスクを処理します。オペレーティング システムはコンピュータの管理者であり、タスクのスケジュール設定、リソースの割り当てと管理、およびコンピュータ ハードウェア全体の命令を担当します。アプリケーション プログラムは特定の機能を持つプログラムであり、プログラムは実行されます。オペレーティング システム上で。

#プロセス

#プロセスは、データ セット上で独立した関数を持つプログラムの動的実行プロセスです。オペレーション システム内でリソースの割り当てとスケジューリングを行うための独立した単位です。アプリケーション実行のキャリアです。プロセスは、リソースを所有して独立して実行できる最小単位です。また、プログラム実行の最小単位でもあります。

プロセスの特性:

  • ダイナミシティ: プロセスはプログラムの実行プロセスであり、一時的であり、寿命があり、生成されます。動的終了;

  • 同時性: 任意のプロセスは他のプロセスと同時に実行可能;

  • 独立性: プロセスはシステム リソースです割り当てとスケジューリングの独立した単位;

  • 構造: プロセスは、プログラム、データ、プロセス制御ブロックの 3 つの部分で構成されます。

#スレッドスレッドとは、プログラム実行における単一の逐次制御プロセスであり、プログラム実行の最小単位です。フロー。プロセッサのスケジューリングとディスパッチの基本単位です。プロセスは 1 つ以上のスレッドを持つことができ、各スレッドはプログラムのメモリ空間 (つまり、プロセスのメモリ空間) を共有します。標準スレッドは、スレッド ID、現在の命令ポインタ (PC)、レジスタ、スタックで構成されます。プロセスは、メモリ空間 (コード、データ、プロセス空間、開いているファイル) と 1 つ以上のスレッドで構成されます。

プロセスとスレッドの違い

    スレッドはプログラム実行の最小単位であり、プロセスはオペレーティング システムによって割り当てられるリソースの最小単位です。
  • プロセスは 1 つ以上のスレッドで構成されます。スレッドはプロセス内のコードの異なる実行ルートです。
  • プロセスは互いに独立していますが、それぞれ同じプロセスの下にあるスレッド プログラムのメモリ空間 (コード セグメント、データ セット、ヒープなど) と一部のプロセス レベルのリソース (開いているファイルやシグナルなど) がそれらの間で共有され、プロセスはそれぞれから見えません。その他;
  • スケジューリングと切り替え: スレッド コンテキストの切り替えは、プロセス コンテキストの切り替えよりもはるかに高速です。
#なぜ JS はシングルスレッドなのでしょうか?

JavaScript は、その誕生以来、ブラウザのスクリプト言語として使用されてきました。主にユーザー インタラクションの処理と DOM の操作に使用されます。これにより、JavaScript はシングルスレッドのみに対応し、それ以外の場合は、ブラウザー用のスクリプト言語として使用されます。非常に複雑な同期問題が発生します。

例: JS がマルチスレッドで、あるスレッドが DOM 要素を変更したいと考えており、別のスレッドが DOM 要素を削除したいと考えている場合、ブラウザは誰の指示をリッスンすればよいかわかりません。したがって、複雑さを避けるために、JavaScript は誕生以来シングルスレッドになるように設計されてきました。

マルチコア CPU のコンピューティング能力を活用するために、HTML5 は Web Worker 標準を提案しています。これにより、JavaScript スクリプトは複数のスレッドを作成できますが、子スレッドはメインスレッドによって完全に制御されるため、 DOM を操作しないでください。したがって、この新しい標準は JavaScript のシングルスレッドの性質を変更するものではありません

ブラウザの原則

フロントエンド エンジニアとして、ブラウザは次のことを行う必要があります。おなじみのブラウザはマルチプロセスです。

#ブラウザ コンポーネント

ユーザー インターフェイス: アドレス バー、進む/戻る/更新/ブックマークを含む

  • ブラウザ エンジン: ユーザー インターフェイスとレンダリング エンジンの間で命令を送信します

  • ##レンダリング エンジン: 要求されたコンテンツの描画に使用されます

  • ネットワーク: http リクエストなどのネットワーク呼び出しを完了するために使用され、プラットフォームに依存しないインターフェイスがあり、さまざまなプラットフォームで動作できます

  • JavaScript インタープリター: JavaScript を解析して実行します。コード

  • ##ユーザー インターフェイス バックエンド: コンボ ボックスやウィンドウなどの基本的なウィジェットと、オペレーティング システムの基礎となるユーザー インターフェイスを描画するために使用されます
  • データ ストレージ: 永続層に属します。ブラウザは、Cookie に似たさまざまなデータをハードディスクに保存します。HTML5 は、軽量で完全なクライアント側ストレージ テクノロジである Web データベース テクノロジを定義します
  • #注: ほとんどのブラウザとは異なり、Google Chrome ブラウザの各タブはレンダリング エンジン インスタンスに対応します。各タブは独立したプロセスです
  • ##ブラウザにはどのようなプロセスが含まれていますか

ブラウザ プロセス

##ブラウザのメイン プロセス (調整と制御を担当)、このプロセスには 1 つのみがあります

  • ブラウザ インターフェイスの表示とユーザー インタラクションを担当します。前方、後方など。

  • 各ページの管理、他のプロセスの作成と破棄を担当します。

  • レンダリング (Renderer) プロセス ユーザー インターフェイスに描画されるビットマップ (ビットマップ)

  • #ネットワーク リソース、ダウンロードなどの管理

  • #サードパーティ プラグイン プロセス

    サードパーティ プラグインの管理を担当します

    GPU プロセス

    3D レンダリングを担当しますおよびハードウェア アクセラレーション (最大 1 つ)

    レンダリング プロセス

    ページ ドキュメントの解析、実行、レンダリングを担当します

    内容スレッドにはレンダリング プロセスが含まれます

    GUI レンダリング スレッド

    #HTML、CSS の解析、DOM ツリーの構築、レイアウト、描画などを主に担当します。 .

    このスレッドは JavaScript エンジン スレッドと相互に排他的です。JavaScript エンジンがスレッドを実行すると、GUI レンダリング スレッドは一時停止されます。タスク キューがアイドル状態の場合、メイン スレッドは GUI レンダリングを実行します

    JavaScript エンジン スレッド

    主に JavaScript スクリプトの処理、コードの実行 (V8 エンジンなど)

    #ブラウザで実行できる JS エンジン スレッドは 1 つだけですJS プログラムは同時に実行されます。つまり、JS はシングルスレッドです。

    JS エンジン スレッドと GUI レンダリング スレッドは相互に排他的に拒否されるため、JS エンジンはページ レンダリングをブロックします

    タイミング トリガー スレッド

    タイマー関数 (setTimeout、setInterval) の実行を担当します

    ブラウザ タイミング カウンタは JS エンジンによってカウントされません (JS はシングルスレッドであるため) 、ブロックされている場合、カウンターの精度に影響します)

    別のスレッドを介してタイミングを計時し、タイミングをトリガーします (タイミングが完了した後、イベント トリガー スレッドのイベント キューに追加して、 JS エンジンはアイドル状態になって実行されます)。このスレッドは、タイマー スレッドとも呼ばれる、時間指定されたトリガー スレッドです。

    W3C は、HTML 標準で、setTimeout が 4ms 未満である必要があると規定しています。時間間隔は次のようにカウントされます。 4ms

    イベント トリガー スレッド

    準備されたイベントを実行のために JS エンジン スレッドに渡す責任を負います

    イベントがトリガーされると、このスレッドは対応するイベントを保留キューの最後に送信し、JS エンジンが処理するのを待ちます。

    非同期リクエスト スレッド

    XMLHttpRequest 接続後、ブラウザは Whenスレッド

    はリクエストステータスの変更を検出します。対応するコールバック関数がある場合、非同期リクエストスレッドはステータス変更イベントを生成し、対応するコールバック関数をキューに入れてJSエンジンの実行を待ちます

    同期と非同期

    JavaScript はシングルスレッドであるため、そのタスクは同期タスクのみであることができないことが決まります。同期タスクを実行するとページ ブロッキングが発生するため、JavaScript タスクは通常 2 つのカテゴリに分類されます。

    同期タスク

    同期タスクはメイン スレッドを参照します。タスクは実行のためにキューに入れられ、次のタスクは前のタスクが実行された後にのみ実行できます。

    非同期タスク

    非同期タスクとは、メイン タスクに入らないタスクを指します。 「タスクキュー」(イベントキュー)に入ったタスクは、「タスクキュー」がメインスレッドに非同期タスクの実行が可能であることを通知した場合にのみ、メインスレッドに入って実行されます。

    一般的な非同期タスク: タイマー、Ajax、イベント バインディング、コールバック関数、Promise、非同期待機など。

    • 同期タスクと非同期タスクは、それぞれ異なる実行に入ります。" " Place」では、メインスレッドに同期的に入り、イベントテーブルに非同期的に入り、関数を登録します。

    • イベント テーブルで指定された処理が完了すると、この関数はイベント キューに移動されます。

    • メイン スレッドのタスクは実行後空になります。タスクはイベント キューに移動して、対応する関数を読み取り、実行のためにメイン スレッドに入ります。

    • 上記のプロセスは継続的に繰り返され、通常はイベント ループと呼ばれます。

    • メインスレッドの実行スタックが空であることをどうやって知ることができるのでしょうか?と疑問に思わずにはいられません。 js エンジンには監視プロセスがあり、メインスレッドの実行スタックが空かどうかを継続的にチェックし、空になったらイベント キューに移動して、呼び出されるのを待っている関数があるかどうかを確認します。

    #マクロタスクとマイクロタスク

    広義の同期タスクと非同期タスクに加えて、JavaScript もより詳細なタスクがあります タスク定義:

    • マクロタスク: グローバル コード、setTimeout、setInterval を含む

    • マイクロタスク : new Promise() .then(callback) process.nextTick()

    異なるタイプのタスクは異なるタスク キューに入ります:

    技術的な回答: JavaScript 実行メカニズム

    次の順序イベントループはjsコードの実行順序を決定します。コード全体 (マクロ タスク) を入力すると、最初のサイクルが開始されます。次に、すべてのマイクロタスクを実行します。次に、再度マクロタスクから開始し、実行するタスクキューの 1 つを見つけて、すべてのマイクロタスクを実行します。

    #実行スタックとタスクキュー

    実行スタック

    JavaScript コードは実行コンテキストで実行されます。JavaScript には 3 つの実行コンテキストがあります:

    • グローバル実行コンテキスト

    • 関数実行コンテキスト、JS 関数が呼び出されるときに関数実行コンテキストが作成されます。

    • eval 実行コンテキスト、eval 関数によって生成されるコンテキスト (あまり使用されません)

    一般的に、JS コードには複数のコンテキストがありますが、これらのコンテキストの実行順序はどうなるのでしょうか?

    スタックが後入れ先出しのデータ構造であることは誰もが知っています。JavaScript の実行スタックもそのようなスタック構造です。JS エンジンがコードを実行すると、グローバル コンテキストが生成されます関数呼び出しが発生すると、関数実行コンテキストが生成され、実行スタックにプッシュされます。エンジンはスタックの最上位から関数の実行を開始し、実行後に実行コンテキストがポップアップ表示されます。

    function add(){
      console.log(1)
      foo()
      console.log(3)
    }
    function foo(){
      console.log(2)
    }
    add()

    上記のコードの実行スタックがどのようなものかを見てみましょう:

    技術的な回答: JavaScript 実行メカニズム

    タスク キュー

    JavaScript のすべてのタスクは同期タスクと非同期タスクに分けられると前述しました。同期タスクは、名前が示すように、すぐに実行されるタスクです。通常、これらは実行のためにメイン スレッドに直接入力されます。非同期タスクはタスク キューに入り、メイン スレッドでタスクが実行されるのを待ってから実行します。

    タスク キューはイベント キューであり、関連する非同期タスクが実行スタックに入ることができることを示します。メインスレッドはタスクキューを読み取り、その中のイベントを読み取ります。

    キューは先入れ先出しのデータ構造です。

    非同期タスクはマクロ タスクとマイクロ タスクに分割できると上で述べました。そのため、タスク キューもマクロ タスク キューとマイクロ タスク キューに分割できます

    • マクロタスク キュー: 比較的大規模な作業を実行します。一般的なものには setTimeout、setInterval、ユーザー インタラクション、UI レンダリングなどが含まれます。

    • マイクロタスク キュー: 小規模な作業を実行します。一般的なものには Promise、 Process.nextTick;

    イベント ループ

    同期タスクは、実行のためにメイン スレッドに直接入れられ、非同期で行われます。タスク (クリック イベント、タイマー、Ajax など) は実行のためにバックグラウンドでハングし、I/O イベントが完了するか、動作イベントがトリガーされるのを待ちます。

    システムは非同期タスクをバックグラウンドで実行します。非同期タスク イベント (または動作イベントがトリガーされる) が発生すると、タスクはタスク キューに追加され、各タスクはコールバック関数によって処理されます。

    ここで、非同期タスクはマクロタスクとマイクロタスクに分けられ、マクロタスクはマクロタスクキューに入り、マイクロタスクはマイクロタスクキューに入ります。

    実行タスク キュー内のタスクは、実行スタック内で具体的に完了します。メイン スレッド内のすべてのタスクが実行されると、マイクロタスク キューが読み込まれます。マイクロタスクがある場合、それらはすべて実行されます。マクロ タスク キューの読み取り

    上記のプロセスは継続的に繰り返されます。これは、よくイベント ループ (イベント ループ) と呼ばれるものです。

    技術的な回答: JavaScript 実行メカニズム

    質問の検証例

    検証用の質問を見てみましょう

    (async ()=>{
        console.log(1) 
      
        setTimeout(() => {
        console.log('setTimeout1')
        }, 0);
      
        function foo (){
            return new Promise((res,rej) => {
                console.log(2)
                res(3)
            })
        }
      
        new Promise((resolve,reject)=>{
        console.log(4)
        resolve() 
        console.log(5)
        }).then(()=> {
        console.log('6')
        })
      
        const res = await foo();
        console.log(res);
        console.log('7')
      
        setTimeout(_ => console.log('setTimeout2'))
    })()

    印刷順序は 1、4、5 です。 ,2,6 ,3,7,setTimeout1,setTimeout2

    分析:

    コードは上から下に実行され、最初に console.log(1) に遭遇し、1 を直接出力し、次に、マクロに属するタイマーに遭遇します。タスクは、マクロ タスク キュー

    に入れてから、Promise に遭遇します。新しい Promise は同期タスクであるため、4 を直接出力します。解決に遭遇すると、これはは後続の then 関数です。マイクロ タスク キューに入れて、再度出力します。5

    次に、await foo を実行します。foo 関数には Promise があります。新しい Promise は同期タスクなので、2 は実行されます。 await は Promise のコールバックを返し、await 後のタスクはマイクロタスク キューに入れられます。

    最後にタイマーに遭遇し、それをマクロ タスク キューに入れます

    実行後スタック タスクが完了したら、まずマイクロ タスク キューに移動してマイクロ タスクの実行を取得し、最初に最初のマイクロ タスクを実行して 6 を出力し、次に 2 番目のマイクロタスクを実行して 3,7

    マイクロタスクが完了した後、出力します。実行された場合は、マクロタスク キューに移動してマクロタスクの実行を取得し、setTimeout1,setTimeout2

    [関連する推奨事項: javascript 学習チュートリアル]

    を出力します。

    以上が技術的な回答: JavaScript 実行メカニズムの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はjuejin.imで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。