この記事では、JavaScript の実行コンテキスト、実行スタック、イベント ループについて説明します。一定の参考値があるので、困っている友達が参考になれば幸いです。
次の概念は、実行コンテキスト
であっても、実行スタック
であっても、仕様では非常に抽象的です。想像に頼った内容が多いので、間違いがあればご指摘ください。
実行コンテキスト
要するに、実行コンテキスト (実行コンテキスト) は、実行可能コードが実行されている環境を抽象化したものです。コード ブロック内の変数の評価をトレースします。これは私がまとめた概念であり、多少不正確な部分があるかもしれませんが、実際の標準定義を参照することもできます。
ただし、一般に、重要な点が 3 つあります。
実行可能コードのみが実行コンテキストを持ちます
実行コンテキストステートフル: 実行状態 (Perform)、一時停止状態 (Suspend)、および再開 (Resume)。 Perfrom 状態の実行コンテキストは、実行中の実行コンテキスト (Running Execution Context) と呼ばれます。
実行コンテキスト は、字句環境とまったく同等ではありません。関係性を言うのは難しいですが、前者が後者を引用しているだけです。
JS スクリプトを実行する場合、複数の実行コンテキストが存在する可能性がありますが、実行コンテキストは 1 つだけです (非同期の場合も同様です。なぜ 4 つ挙げられているかについては、 ..3 四大王がいるのは常識ではないでしょうか...)。
そして、ES 仕様では、実行可能コードが次のように規定されています:
var g=111 function f(){ console.log(g); for(let i =0; i 上記のコードを実行すると、2 つの実行コンテキストのみが生成されます: <p></p>
f
とマークされた行をコメントアウトすると、実行コンテキストは 1 つだけになります。関数 f
はまったく実行されず、当然、対応する実行コンテキストも存在しないためです。この中で唯一紛らわしいのは、これが for ループ
であることですが、 これはまったく実行可能コードではないため、関数実行コンテキストの一部です
。
実行コンテキストは次のように抽象化できます:
ExecutionContext = { State: LexEnv = { This: , OuterEnv: , DecRec:{ //... identifiername-variable } } VaEnv = { This: , OuterEnv: , VarRec:{ //... identifiername-variable } } }
実際には、実行コンテキストには 2 つあります。非常に重要です。コンポーネント:
LexicalEnvironmentComponent (字句環境コンポーネント) および VariableEnvironmentComponent
(変数環境コンポーネント)。字句環境コンポーネントは 現在のコード
の 字句環境 (LexEnv) を指し、変数環境コンポーネントは ## の 変数環境を指します。 #現在のコード
(VarEnv)。 実行コンテキスト
についていくつか言わなければならないことがあります。非常に重要な部分の 1 つは
ですが、実行コンテキスト##には関連するコンテンツはありません#で見られました。ただし、 スコープ チェーン は存在します。これは [[Scope]] 内部プロパティにあり、 ブラウザ を通じて直接確認できます。 しかし、このように理解することもできます。実行コンテキストが作成されると、現在の語彙環境の
LexEnv だけでなく、LexEnv.OutEnv# も作成されます。 ##, ## が作成され、 #LexEnv.OutEnv.OutEnv
実行コンテキストの作成と破棄
1. 新しい実行コンテキスト (ExecutionContext、EC) を作成します。
3. 実行コンテキストの LexicalEnvironmentComponent
およびVariableEnvironmentComponent
を次のLexEnv
およびVarEnv## にポイントします。現在の環境。#middle. 4. 新しい実行コンテキストを
実行スタック
にプッシュし、ランタイム実行コンテキスト
になります。 5. 実行可能コード ブロック内の識別子をインスタンス化して初期化します:
現在の字句環境で宣言されたすべての識別子を収集します #Into DecRec
var
で宣言されたすべての識別子は、識別子名 が検出処理されます。 ##let/const/... が VarNames の識別子と同じである場合、エラーが報告されます。 DecRec で識別子をインスタンス化し、
uninitialized
に設定します。 VarNames
の識別子は
に直接初期化されます。
对于function
声明的函数,将直接指向函数对象,并也会绑定到ObjRec中,这是浏览器默认行为。
6、运行代码。
非var声明的标识符会在声明处进行初始化(默认为undefined
)。
完成所有变量的赋值,并可能会一直在变化。
7、运行完毕从 执行栈
中弹出。
备注:
This
绑定,大部分情况可以用过去的说法解释,然而某些情况下却不尽然。执行栈与事件循环
执行栈(Execution Stack)就是由执行上下文构成的堆栈,类似于Call Stack
。
1、当Javascript引擎
遇到一段可执行代码时,新建一个执行上下文。
2、将它推入执行栈中。并设置为运行时执行上下文。
3、执行上下文运行完毕,弹出销毁恢复并将原执行上下文设为运行时。
总觉得这些没什么好说的,但是水一下吧
执行栈最重要的部分并非是执行栈概念本身,而是与任务队列的关系,它是事件循环的入门关键概念之一。
众所周知,Javascript语言是单线程的,此处的执行栈就相当于主线程的调用栈,也是唯一一个调用栈,至于什么是主线程可以查阅相关资料,这里有些超纲了……
那么javascript是如何实现异步的?
确切来说,这不是Javascript核心的部分,它是结合浏览器API(如Web Worker, Browser-context了解一下)实现的。
在事件循环中(事件处理过程),有两个极其重要的概念:
这两个概念,是抽象滴。
在Javascript中,一个任务也可以称之为事件,通常是一个函数回调,由许多任务组成的队列,就是所谓的任务序列了。任务序列有很多分类,例如:作业序列(Job Quenue)、消息序列(Message Quenue),本质没区别。
不必再深入了解,现在需要记住的是:一个任务序列中的任务如果想要被执行,就必须将它取出放入执行栈中。
例如下面的代码:
var temp = 10; console.log('push task1'); setTimeout(function task1(){ temp+=10; console.log(temp+'task1 okay! '); },1000) console.log('taskquenue=[task1]; push task2'); setTimeout(function task2(){ temp*=10; console.log(temp+'task2 okay! '); },500) console.log('taskquenue=[task1,task2]; push task3'); setTimeout(function task3(){ temp*= -0.2; console.log(temp+'task3 okay! '); },1500) console.log('taskquenue=[task1, task2,task3]');
输出如下:
push task1 taskquenue=[task1]; push task2 taskquenue=[task1,task2]; push task3 taskquenue=[task1, task2,task3] 100task2 okay! 110task1 okay! -22task3 okay!
setTimeout
是一个定时器,它能够将任务放到任务队列中。如图:
task1
:task2
:task3
:执行到此处, task1
、task2
和task3
都被放入了任务队列; 然后执行栈全部执行完毕后,开始处理任务队列中的任务。
为什么任务队列中的任务必须在执行栈空时后执行呢?
C
や Java
などの他のマルチスレッド言語を参照するか、オペレーティング システムの内容を確認することができます。 ここでタスクの処理を開始します:
task2
:task1
:task3
:わかりました、イベント ループ# # #それでおしまい。 その後、
Javascript エンジンは スリープ フェーズに入ります (Javascript エンジンは終了しません!)、新しいタスクが実行されるのを待ってから、次のイベントを開始しますループ。 備考:
3 番目の記事、不意を突かれた イベント ループ 、一度に多くのことを深く掘り下げるようです...しかし、これは最も 不合理なプログラミング配置だと思います。ほとんどのドキュメントでは、タスク シーケンスと コール スタック#が分離されています。 ## ですが、~~_____~~ では、これらは 1 つである必要があり、都合のよい理由で分離してはなりません 。 JavaScript の詳細については、仕様を読むだけでなく、JS エンジン の実装ドキュメントも読むことをお勧めします。一部の高度な内容は仕様には含まれていませんが、これらのドキュメントには含まれています。ドキュメント (Google で検索してください。Baidu でも検索できます)。
JavaScript エンジン に興味がある場合は、次を参照してください:
MDN About_JavascriptChromium V8 リファレンス
JavaScript ビデオ チュートリアル
以上がJS の実行コンテキスト、実行スタック、イベント ループを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。