ホームページ > 記事 > ウェブフロントエンド > JavaScriptの動作仕組みの概要(コード例)
この記事は、JavaScript の動作メカニズム (コード例) をまとめたものです。必要な方は参考にしていただければ幸いです。
JavaScript の動作メカニズムについて説明する前に、コードの一部を見てみましょう:
console.log(1) Promise.resolve().then(function () { console.log(2) }) new Promise(function(resolve, reject){ console.log(3) resolve() }).then(function () { console.log(4) setTimeout(function () { console.log(5) }) }) console.log(6) setTimeout(function () { Promise.resolve().then(function () { console.log(7) setTimeout(function () { console.log(8) }) }) })
このコードを見て、正しい出力シーケンスがわかれば。つまり、この分野はほぼマスターしたことになります。 (結果を確認するには最後まで直接アクセスしてください)
さて、本題に取り掛かりましょう。
その仕組みについて説明する前に、いくつかの概念を見てみましょう。
実行コンテキスト (実行コンテキスト)
実行コンテキストは、単なる実行環境です。グローバル環境、関数環境、評価関数環境があります。これは、JavaScript エンジンがスクリプトを実行するときに作成されます。
実行スタック
実行スタックは、一般にコール スタックとも呼ばれ、LIFO (後入れ先出し) を備えたデータ構造です。コードの実行時に作成された実行コンテキストを格納します。
マイクロタスク (micro task) とマクロタスク (macro task)
#javasript のタスクは 2 つに分かれています。マイクロタスクとマクロタスク タスクには2種類あり、これら2つのタスクは実行タイミングが異なるため、jsではどれがマクロタスクでどれがマイクロタスクであるかを区別することが非常に重要です。一般的なマクロ タスクには、スクリプト タスク、setTimeout、ajax などがあります。一般的なマイクロ タスクとしては、Promise.resolve().then()、process.nextTick、MutationObserver などがあります。
イベント ループ (イベント ループ)
js はシングルスレッドです。つまり、一度に 1 つのタスクしか処理できません。しかし、js が配置されているホスト環境 (いわゆるブラウザ) はシングルスレッドではありません (ホスト環境はここではブラウザについてのみ説明します)。 setTimeout、イベントリスナーなどのタスクが発生したとき。それはブラウザに「兄弟、お願いがあって、それが終わったら先に他のことをするから教えてください」と伝えます。ブラウザは「任せてください、弟さん、それが終わったらタスクキューに入れて自分で取りに行きます」と応答します。したがって、js はスクリプト タスクの実行を開始し、実行が完了した後、マイクロタスクがあるかどうかを確認し始めます。存在しない場合は、各マクロタスクの実行後に、マクロタスクをタスク キューからフェッチし始めます。マイクロタスクがあるかどうかを確認します。ある場合は、実行が完了したら、マクロタスクを再度実行します。次のとおりです:
これらの概念を理解すると、JavaScript がコードをどのように実行するかを調べることがより簡単になり、より楽しくなります。始めましょう
console.log(1) Promise.resolve().then(function () { console.log(2) }) new Promise(function(resolve, reject){ console.log(3) resolve() }).then(function () { console.log(4) setTimeout(function () { console.log(5) }) }) console.log(6) setTimeout(function () { Promise.resolve().then(function () { console.log(7) setTimeout(function () { console.log(8) }) }) })
JS エンジンがこのコードを実行すると、まずグローバル実行コンテキストがスタックにプッシュされます:
次に、実行中に console.log 関数が発生し、それをスタックにプッシュします。
この時点では、console 関数を直接実行します。 、出力1。次に、コンソール関数がスタックから飛び出します。
実行を継続し、Promise.resolve().then() に遭遇します。 ( ).then() はスタックにプッシュされます (ここでは、描画の便宜のために全体として考えています。そうしないと、大量の絵を描画する必要があります)。
次に、Promise.resolve().then() を実行します。前述したように、この then() 関数はマイクロタスクであり、渡されたコールバック関数を渡します。マイクロタスクキューに参加します。
その後、Promise.resolve().then() がスタックからポップされます。
次に、promise のコンストラクターを実行すると、このコンストラクターはマクロ タスクであり、渡された関数をスタックに直接プッシュします。
コンソール関数を実行して 3 を出力します。実行後、コンソール関数がスタックからポップされ、次に、resolve() 関数が実行されてスタックからポップされます。
その後、 then 関数の実行を続け、 then 関数に渡されたパラメータ関数をマイクロタスク キューに入れます。
引き続き、以下の実行に進みます。 console.log(6) に遭遇すると、何も言わずにスタックに直接プッシュされ、実行され、6 を出力し、スタックからポップアウトされます。
接着,引擎碰到了setTimeout函数,这家伙是个宏任务,但同时它会将传递给它的函数,加入到任务队列中:
好了,到此第一波宏任务就全部执行完毕。接着,引擎就会去看一下微任务队列中有没有任务,如果有的话,执行它们。
现在看到的是,微任务队列中有两个任务。按照队列的先入先出规则,先从function () {console.log(2)}开始执行。先是函数入栈,然后执行函数,输出2,然后函数出栈。
接着执行下面这段代码:
console.log(4) setTimeout(function () { console.log(5) })
先从console.log(4)开始,先将它入栈,然后执行它,输出4,然后函数出栈。
接着执行:
setTimeout(function () { console.log(5) })
将
function () { console.log(5) }
加入到任务队列中去
先执行:
function(){ Promise.resolve().then(function () { console.log(7) setTimeout(function () { console.log(8) }) }) }
这里执行这个函数的时候遇到一个微任务,将这个微任务添加到微任务队列,如下:
这批次的宏任务就执行完毕了,接着就回去检查微任务队列中有没有待执行的任务。一看还真有两个小可爱等待执行,于是没什么好说的,直接拧出去就执行
先是执行console.log(7),然后输出7。接着执行setTimeout,将传递给他的任务添加到任务队列中去:
最后就剩这两个函数了,按照队列的先入后出一次执行吧,输出5和8。
好了,最后的结果就是1,3,6,2,4,7,5,8。你写对了了吗?
以上がJavaScriptの動作仕組みの概要(コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。