JavaScriptの操作メカニズムに関する深い理解

JavaScriptの操作メカニズムに関する深い理解

序文

  • この記事は、チームの新参者をトレーニングする際に書かれているため、実際、この記事の対象者は、JavaScriptの操作メカニズムを理解していないか、理解しにくい小さなパートナーです言い換えれば、実際の原則は、この記事の説明と完全には一致していません。中学校の教科書や大学の教科書と同じように、大学の教師は、高校のいくつかのことは特定の理想的な状況下で得られた結論であるとあなたに言います。この記事は同じです。
  • この記事の目的は、JavaScriptを読んだ後、誰もがJavaScriptの操作メカニズムをより直感的かつ迅速に理解できるようにすることですが、さらに重要なことは、自分それを行うことです。実際に問題を発見して改善できるのは練習だけです:)
  • 私はあなたのサポートとフィードバックを受け取りました、どうもありがとうございました:)

JavaScriptの動作メカニズムを理解するには、次の点を深く理解する必要があります。

  • JavaScriptのシングルスレッドメカニズム
  • タスクキュー(同期タスクと非同期タスク)
  • イベントとコールバック関数
  • タイマー
  • イベントループ

JavaScriptのシングルスレッドメカニズム

JavaScriptの言語機能の1つ(および言語のコア)はシングルスレッドです。シングルスレッドとは何ですか?簡単に言えば、同時に実行できるのは1つだけです。複数のタスクがある場合、次のタスクを実行する前に、1つの順序で1つずつしか完了できません。

JavaScriptの単一スレッドは、その言語の使用法に関連しています。ブラウザスクリプト言語としてのJavaScriptの主な目的は、ユーザーの操作を完了し、DOMを操作することです。これにより、シングルスレッドのみが可能であると判断されます。そうしないと、複雑な同期の問題が発生します。

JavaScriptに同時に2つのスレッドがあると想像してください。一方のスレッドは特定のDOMノードにコンテンツを追加する必要があり、もう一方のスレッドの操作はこのノードを削除することです。それでは、ブラウザは誰を取得する必要がありますか?

そのため、複雑さを回避するために、JavaScriptは開始以来シングルスレッド化されてきました。

CPU使用率を改善するために、HTML5はJavaScriptスクリプトが複数のスレッドを作成できるようにするWebワーカー標準を提案していますが、子スレッドはメインスレッドによって完全に制御され、DOMを操作してはなりません。したがって、この標準はJavaScriptシングルスレッドの性質を変更しません。

タスクキュー

タスクを1つずつ完了するということは、完了するタスクをキューに入れる必要があるということですが、なぜそれらをキューに入れる必要があるのでしょうか。

通常、キューイングには2つの理由があります。

  • タスクの計算が大きすぎて、CPUがビジーです。
  • タスクに必要なものは準備ができており、実行を継続できず、CPUがアイドル状態になり、入力デバイスと出力デバイス(I / Oデバイス)を待機します。>たとえば、一部のタスクでは、続行する前にデータを取得するためにAjaxが必要です

その結果、JavaScriptの設計者は、この時点で、後で準備ができたタスクを実行して運用効率を向上させること、つまり、待機中のタスクを一時停止して脇に置き、必要なものを取得してから実行できることにも気づきました。これは、相手が電話に出たときに離れて、別の着信があるので、現在の電話を切り、電話が終わるのを待ってから、前の電話に接続し直すようなものです。

そのため、同期と非同期の概念が出現し、タスクは2つのタイプに分けられます。1つは同期タスク(同期)で、もう1つは非同期タスク(非同期)です。

  • 同期タスク:実行する必要のあるタスクはメインスレッドで次々にキューに入れられ、前のタスクは次のタスクが実行される前に完了します
  • 非同期タスク:すぐには実行されないが実行する必要のあるタスクは「タスクキュー」に格納されます。「タスクキュー」はメインスレッドにいつ、どの非同期タスクを実行できるかを通知し、タスクはメインスレッドに入り、実行されます。>すべての同期実行は、非同期タスクなしの非同期実行と見なすことができます

具体的には、非同期実行は次のとおりです。

  • すべての同期タスクはメインスレッドで実行され、実行スタック(実行コンテキストスタック)を形成します。

    つまり、すぐに実行できるすべてのタスクがメインスレッドのキューに入れられ、1つずつ実行されます。

  • メインスレッドに加えて、「タスクキュー」もあります。非同期タスクの実行結果がある限り、イベントは「タスクキュー」に配置されます。

    つまり、各非同期タスクの準備ができると、一意のフラグが設定され、このフラグは対応する非同期タスクを識別するために使用されます。

  • 「実行スタック」内のすべての同期タスクが実行されると、システムは「タスクキュー」を読み取り、その中にあるイベントを確認します。これらの対応する非同期タスクは、バギングの待機を終了し、実行スタックに入り、実行を開始します。

    つまり、メインスレッドは前のタスクを終了した後、「タスクキュー」内のフラグを調べて、対応する非同期タスクをパッケージ化して実行します。

  • メインスレッドは上記の3つのステップを繰り返し続けます。

    メインスレッドが空である限り、メインスレッドは「タスクキュー」を読み取ります。このプロセスは継続的に繰り返され、これがJavaScriptの動作方法です。

イベントとコールバック関数

出来事

「タスクキュー」はイベントキューです(メッセージキューとしても理解できます)。IOデバイスがタスクを完了すると、「タスクキュー」に時間が追加され、関連する非同期タスクが「実行スタック」に入ることができることを示します。 。次に、メインスレッドは「タスクキュー」を読み取り、その中にあるイベントを確認します。

IOデバイスのイベントに加えて、「タスクキュー」内のイベントには、ユーザーが生成したイベント(マウスクリック、ページスクロールなど)も含まれます。コールバック関数が指定されている限り、これらのイベントは「タスクキュー」に入り、メインスレッドが読み取るのを待ちます。

折り返し電話

いわゆる「コールバック」(コールバック)は、メインスレッドによって一時停止されるコードです。非同期タスクはコールバック関数を指定する必要があります。メインスレッドが非同期タスクの実行を開始すると、対応するコールバック関数が実行されます。

「タスクキュー」はファーストイン、ファーストアウトのデータ構造であり、最初のイベントはメインスレッドによって最初に読み取られます。メインスレッドの読み取りプロセスは基本的に自動です。実行スタックがクリアされている限り、「タスクキュー」の最初のイベントが自動的にメインスレッドに入ります。ただし、「タイマー」が含まれている場合、メインスレッドは最初に実行時間をチェックする必要があり、特定のイベントは指定された時間の後にのみメインスレッドに戻ることができます。

イベントループ

メインスレッドは「タスクキュー」からイベントを読み取ります。このプロセスは循環的であるため、操作メカニズム全体は「イベントループ」(イベントループ)とも呼ばれます。

イベントループをよりよく理解するために、以下のフィリップロバーツのスピーチの写真を参照してください。

イベントループ

上の図では、メインスレッドが実行されているときに、ヒープ(ヒープ)とスタック(スタック)が生成されます。スタック内のコードは、さまざまな外部APIを呼び出し、さまざまなイベント(クリック、ロード、完了)を「タスクキュー」に追加します。 。スタック内のコードが実行されると、メインスレッドは「タスクキュー」を読み取り、それらのイベントに対応するコールバック関数を順番に実行します。

実行スタック(同期タスク)内のコードは、常に「タスクキュー」(非同期タスク)を読み取る前に実行されます。

var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function (){};
req.onerror = function (){};
req.send();

上記のコードのreq.sendメソッドは、サーバーにデータを送信するAjax操作です。これは非同期タスクです。つまり、システムは、現在のスクリプトのすべてのコードが実行された後にのみ「タスクキュー」を読み取ります。したがって、以下の記述と同等です。

var req = new XMLHttpRequest();
req.open('GET', url);
req.send();
req.onload = function (){};
req.onerror = function (){};

つまり、指定されたコールバック関数の一部(onloadおよびonerror)は、実行スタックの一部であり、システムはそれらの実行後に常に「タスク」を読み取るため、send()メソッドの前後では関係ありません。キュー"。

タイマー

「タスクキュー」は、非同期タスクのイベントを配置するだけでなく、時間指定イベントを配置することもできます。つまり、特定のコードが実行されるまでの時間を指定します。これはタイマー機能と呼ばれ、定期的に実行されるコードです。

SetTimeout()またsetInterval()、指定された時間の後に単一または繰り返しの呼び出しを登録するために使用できる関数、それらの内部操作メカニズムはまったく同じです。違いは、前者によって指定されたコードが1回実行され、後者は指定されたミリ秒数の間隔で繰り返し呼び出されることです。

setInterval(updateClock, 60000); //60秒调用一次updateClock()

これらはクライアント側JavaScriptの重要なグローバル関数であるため、Windowオブジェクトのメソッドとして定義されています。

しかし、一般的な機能として、それは実際にはウィンドウに対して何もしません。

WindowオブジェクトのsetTImeout()メソッドは、指定されたミリ秒数後に実行される関数を実装するために使用されます。したがって、2つのパラメーターを受け入れます。1つ目はコールバック関数で、2つ目は実行を遅らせるミリ秒数です。setTimeout()そして、この関数の実行setInterval()clearTimeout()キャンセルするために渡すことができる値を返します

console.log(1);
setTimeout(function(){console.log(2);}, 1000);
console.log(3);

setTimeout()2行目の実行が1000ミリ秒に延期されているため、上記のコードの実行結果は1、3、2になります。

setTimeout()2番目のパラメーターが0に設定されている場合、現在のコードが実行された後(実行スタックがクリアされた後)、指定されたコールバック関数がすぐに実行されることを意味します(0ミリ秒間隔)。

setTimeout(function(){console.log(1);}, 0);
console.log(2)

上記のコードの実行結果は常に2、1です。これは、システムが2行目が実行された後にのみ、「タスクキュー」でコールバック関数を実行するためです。

要するに、setTimeout(fn,o)メインスレッドの利用可能な最も早い空き時間に実行されるタスクを指定すること、つまり、できるだけ早く実行することを意味します。「タスクキュー」の最後にイベントを追加するため、同期タスクと「タスクキュー」の既存のイベントが処理されるまで実行されません。

HTML5規格で指定されsetTimeout()ている2番目のパラメータの最小値(最短間隔)4ミリ秒以上である必要があります。この値よりも小さい場合は、自動的に増加します。

イベントsetTimeout()のみが「タスクキュー」挿入され、メインスレッドは、現在のコード(実行スタック)が実行された後にのみ、指定されたコールバック関数を実行することに注意してください現在のコードに時間がかかる場合は、長時間待たなければならない可能性があるため、setTimeout()指定した時間にコールバック関数が実行されることを保証する方法はありません

歴史的な理由から、setTimeout()sum setInterval()の最初のパラメーターは文字列として渡すことができます。これを行うと、指定されたタイムアウト期間または間隔の後に文字列が評価されます(実行と同等eval())。

タイマーの動作原理を深く理解するために、jQueryの作成者であるJohn Resigによる記事を以下に示します:http://ejohn.org/blog/how-javascript-timers-work/

私もこの記事を自分で翻訳しました。質問がある場合は、訂正してください:http://guoxunique.com/2016/12/07/how-javascript-timers-work/

Ruanyifeng先生のブログ投稿http://www.ruanyifeng.com/blog/2014/10/event-loop.htmlを参照してください。

「JavaScript決定ガイド」を参照してください

おすすめ

転載: blog.csdn.net/Amos_liu/article/details/53560434