JavaScriptの構文解析動作原理

それはJavaScriptの原則を実行するとなると、当然のことながら、その上のJSエンジン、コンテキストを実行しているの概念、シングルスレッド、イベントループ、イベントドリブン、コールバックを周りに開いていません。本明細書で主に記事を参照して[1,2]。

より良いJavaScriptがどのように機能するかを理解するために、我々は、最初に次の概念を理解する必要があります。

  • JSエンジン(JSエンジン)

  • ランタイム(実行中のコンテキスト)

  • コールスタック(コールスタック)

  • イベントループ(イベントループ)

  • コールバック(コールバック)

1.JSエンジン

簡単に言えば、それはそれを行うには、コンピュータを作るために実行可能なマシンコードにコードをコンパイルするコンパイラによって、JS JSコード字句解析、文法などのメインエンジンです。

最も人気のある非V8エンジンは、JS、Chromeブラウザに他ならないとのNode.jsは、エンジンV8エンジンに使用されています。エンジンの構造は、単に以下の図で表されてもよいです。

c3237bb1339d4ddba3289585eb525d7c


JVMは、仮想マシンとして、JSエンジンはまた、ヒープ(メモリヒープ)とスタック(コールスタック)の概念を持っていたようです。

  • スタック。後>メソッド呼び出し - - メソッド呼び出しを格納し、基本的なデータ・タイプ(例えばVARのA = 1)は自動的にオフに破壊されるメソッド呼び出しの終了と、内部スタックに格納される(プッシュ>ポップ)。

  • ヒープ。オブジェクト空間へのJSエンジンは、ヒープメモリ上に割り当てられています。VaRのFOO = {名:「fooが」}次に、FOOオブジェクトはヒープに格納されていると指摘しました。

また、JSに存在クロージャの概念は、存在する場合、次いで、スタックに格納されたクロージャの基本的な変数タイプ。詳細はこちら1,3を見ることができます

クロージャの場合については、に関連する変数をキャプチャ我々はことを知っているローカル変数は、最も単純なケースであるスタック上に直接保存されます。そして、変数キャプチャを持つ条件とクロージャの存在のために、変数の条件をキャッチしてみてください。

function foo () { var x; // local variables
 var y; // captured variable, bar中引用了y
 function bar () { // bar 中的context会capture变量y
 use(y);
 } return bar;
}
复制代码

如上述情况,变量y存在与bar()的闭包中,因此y是captured variable,是存储在堆中的。

2.RunTime

JS在浏览器中可以调用浏览器提供的API,如window对象,DOM相关API等。这些接口并不是由V8引擎提供的,是存在与浏览器当中的。因此简单来说,对于这些相关的外部接口,可以在运行时供JS调用,以及JS的事件循环(Event Loop)和事件队列(Callback Queue),把这些称为RunTime。有些地方也把JS所用到的core lib核心库也看作RunTime的一部分。

5927efdf625945c29bef4bd4cf7d2d31


同样,在Node.js中,可以把Node的各种库提供的API称为RunTime。所以可以这么理解,Chrome和Node.js都采用相同的V8引擎,但拥有不同的运行环境(RunTime Environments)[4]。

3.Call Stack

JS被设计为单线程运行的,这是因为JS主要用来实现很多交互相关的操作,如DOM相关操作,如果是多线程会造成复杂的同步问题。因此JS自诞生以来就是单线程的,而且主线程都是用来进行界面相关的渲染操作 (为什么说是主线程,因为HTML5 提供了Web Worker,独立的一个后台JS,用来处理一些耗时数据操作。因为不会修改相关DOM及页面元素,因此不影响页面性能),如果有阻塞产生会导致浏览器卡死。

如果一个递归调用没有终止条件,是一个死循环的话,会导致调用栈内存不够而溢出,如:

function foo() {
 foo();
}foo();复制代码

例子中foo函数循环调用其本身,且没有终止条件,浏览器控制台输出调用栈达到最大调用次数。

293fb12d924c4391ae8f8809cf5182b1


JS线程如果遇到比较耗时操作,如读取文件,AJAX请求操作怎么办?这里JS用到了Callback回调函数来处理。

对于Call Stack中的每个方法调用,都会形成它自己的一个执行上下文Execution Context,关于执行上下文的详细阐述请看这篇文章

4.Event Loop & Callback

JS通过回调的方式,异步处理耗时的任务。一个简单的例子:

var result = ajax('...');
console.log(result);
复制代码

此时并不会得到result的值,result是undefined。这是因为ajax的调用是异步的,当前线程并不会等到ajax请求到结果后才执行console.log语句。而是调用ajax后请求的操作交给回调函数,自己是立刻返回。正确的写法应该是:

ajax('...', function(result) { console.log(result);
})
复制代码

此时才能正确输出请求返回的结果。

JS引擎其实并不提供异步的支持,异步支持主要依赖于运行环境(浏览器或Node.js)。

So, for example, when your JavaScript program makes an Ajax request to fetch some data from the server, you set up the “response” code in a function (the “callback”), and the JS Engine tells the hosting environment: “Hey, I’m going to suspend execution for now, but whenever you finish with that network request, and you have some data, please call this function back.”

The browser is then set up to listen for the response from the network, and when it has something to return to you, it will schedule the callback function to be executed by inserting it into the event loop.

上面这两段话摘自于How JavaScript works,以通俗的方式解释了JS如何调用回调函数实现异步处理。

所以什么是Event Loop?

Event Loop只做一件事情,负责监听Call Stack和Callback Queue。当Call Stack里面的调用栈运行完变成空了,Event Loop就把Callback Queue里面的第一条事件(其实就是回调函数)放到调用栈中并执行它,后续不断循环执行这个操作。

一个setTimeout的例子以及对应的Event Loop动态图:

console.log('Hi');
setTimeout(function cb1() { 
 console.log('cb1');
}, 5000);console.log('Bye');
复制代码

b63e76f509aa49f393b33ea75466f48f


setTimeout有个要注意的地方,如上述例子延迟5s执行,不是严格意义上的5s,正确来说是至少5s以后会执行。因为Web API会设定一个5s的定时器,时间到期后将回调函数加到队列中,此时该回调函数还不一定会马上运行,因为队列中可能还有之前加入的其他回调函数,而且还必须等到Call Stack空了之后才会从队列中取一个回调执行。

所以常见的setTimeout(callback, 0) 的做法就是为了在常规的调用介绍后马上运行回调函数。

console.log('Hi');
setTimeout(function() { console.log('callback');
}, 0);console.log('Bye');// 输出// Hi// Bye// callback复制代码

在说一个容易犯错的栗子:

for (var i = 0; i < 5; i++) {
 setTimeout(function() { console.log(i);
 }, 1000 * i);
}	
// 输出:5 5 5 5 5复制代码

栗は、最初の反応は、それがなければならないことであり、出力0,1,2,3,4上にはありません。しかし、JSのサイクルタイムをカーディングした後、理解しやすいはずです。

逐次ループを実行する{...}直接イベントキューにタイマコールバック関数後の時間である方法、等(私は++; iが5 <VAR I = 0)するための第1の実行コールスタックコールスタックを出します。forループを実行する場合、iの値は、すべての5の最終的な出力5となっています。

タイマーについては、この興味深い記事を読むことができます

最後に、イベントループに関して、あなたはこのビデオを参照することができます。これまでのところ、彼はイベントループは、フロントエンド、ブラウザのイベントループであることを特徴とする、イベントNodejsに関するループの詳細は説明し、デザインパターンのNode.js私の他の記事を参照してください炉(イベントループ)。両者の違いを比較すると、関連する概要と比較を行うために、イベントループの2種類のイベントループを知らないこの記事を閲覧することができます。

概要

主に以下の分野では、JSの動作原理を要約すると:

  • JSエンジンが行うことができますマシンコードマシンにJSコードの責任であり、ここでは提供その動作環境JSコードの呼び出しによって、一部のWeb APIは、ブラウザを指します。

  • JSは、単一のスレッド、スタックたびに取ら呼番号からの呼び出しです。現在のコードは非常に時間がかかる場合は、ブラウザが現在のスレッドカトンをブロックするようになります。

  • コールバックイベントループを待って、イベントキューに追加することで機能し、コールスタックコールを出します。唯一のイベントループコールスタックに耳を傾けるが空である、それは、コールスタック内のコールバック関数にチームのヘッドからイベントキューから来ます。

db34b17aa11149599b1a55120cb5de27


おすすめ

転載: blog.51cto.com/14516511/2440091