JavaScript parsing operation principle

When it comes to running JavaScript principle, of course, is not open around JS engine, the concept of running context, single-threaded, event loop, event driven, callback and so on. Herein primarily with reference to article [1,2].

In order to better understand how JavaScript works, we must first understand the following concepts.

  • JS Engine (JS engine)

  • Runtime (running context)

  • Call Stack (call stack)

  • Event Loop (event loop)

  • Callback (callback)

1.JS Engine

In simple terms, it is the main engine of the JS JS code lexical analysis, grammar, etc., by the compiler to compile the code into executable machine code to make a computer to do it.

The most popular non-V8 engine is none other than JS, Chrome browser and the Node.js is used in engine V8 engine. The structure of the engine may be simply represented by the following diagram:

c3237bb1339d4ddba3289585eb525d7c


As JVM as a virtual machine, JS engine also has the concept of heap (Memory Heap) and Stack (Call Stack) is.

  • Stack. After> method call - - where to store the method call, and basic data types (e.g. var a = 1) is stored on the stack inside, with the end of the method call will be automatically destroyed off (push> pop ).

  • stack. JS engine to the object space is allocated on the heap memory. The var foo = {name: 'foo'} then the foo object pointed to is stored in a heap.

Furthermore, the concept of closures present in JS, if present, the basic variable types of closure which then also stored in the stack. Details can be seen here 1,3

About the case of closures, to relate to Captured the Variables . We know that Local Variables is the simplest case, is stored directly on the stack. And Captured Variables for the presence of conditions and closures with, try catch variable conditions.

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复制代码

The chestnut is not above output 0,1,2,3,4, the first reaction is that it should be. But after carding a cycle time of JS, it should be easy to understand.

Call stack performed first for (var i = 0; i <5; i ++) {...} method, which is the time after the timer callback function directly into the event queue, and the like for sequentially executing the loop put out the call stack. When executing the for loop, the value of i has become 5, the final output of all 5.

About timer and can read this interesting article

Finally, with regard to Event Loop, you can refer to this video. So far, he said the event loop is a front-end browser event loop, Loop details about the Event Nodejs explained, see my other article Node.js design pattern: Reactor (Event Loop). Comparing the difference between the two can view this article you do not know Event Loop, two kinds of event loop to do the relevant summary and comparison.

to sum up

To sum up, the operating principle of JS mainly in the following areas:

  • JS engine is responsible for the JS code into machine code machine can do, and some WEB API by its operating environment JS code calls provided here refers to the browser.

  • JS is a single thread, the stack each time a call from the call code taken. If the current code is very time-consuming, it will cause the browser to block the current thread Caton.

  • The callback function by adding to the event queue, waiting for Event Loop and put out the call stack call. Only Event Loop listen to the call stack is empty, it will come from the event queue from the team head into the callback function in the call stack.

db34b17aa11149599b1a55120cb5de27


Guess you like

Origin blog.51cto.com/14516511/2440091