JavaScript内部:在浏览器的引擎盖下

Intro

JavaScript很奇怪。有些人喜欢它,另一些人讨厌它。它具有许多独特的机制,这些机制不存在,并且没有其他流行语言。例如,代码执行订单有时可能是不直觉的,绝对是突出的。

了解浏览器环境,其组成的内容以及其工作方式将使您更有信心编写JavaScript并为可能发生的潜在问题做好准备。

在这件作品中,我将尝试阐明Chrome浏览器引擎盖下的情况。我们将看看:

  • V8 Javascript Engine — compilation steps, heap and memory management, and call stack.
  • Browser runtime — concurrency models, event loops, and blocking and non-blocking code.

JavaScript Engine

The most popular JavaScript engine is V8 which is written in C++ and used by Chromium-based browsers such as Chrome, Opera, and even Edge.

基本上,该引擎是一个将您的JavaScript转换为机器代码并在计算机中央处理单元(CPU)上执行结果的程序。

Compilation

当您的JavaScript文件由浏览器加载时,V8的解析器将其转换为抽象语法树(AST)。该树由点火(点火)使用 - 产生字节码的解释器。字节码是通过编译到非优化的机器代码来执行的机器代码的抽象。V8在主线程中执行它,而优化编译器TurboFan在另一个线程中进行了一些优化,并产生了优化的机器代码。

This pipeline is calledjust-in-time (JIT) compilation.

致电堆栈

JavaScript是一种带有单个呼叫堆栈的单线程编程语言。这意味着您的代码是同步执行的。每当函数运行时,它将在任何其他代码运行之前完全运行。

当V8调用您的JavaScript函数时,它必须在某个地方存储运行时数据。致电堆栈是由堆栈帧组成的内存中的位置。每个堆栈框架对应于尚未以返回终止的函数的调用。堆栈框架由:

  • local variables
  • 参数参数
  • return address

如果我们执行功能,则V8将在堆栈顶部推动框架。当我们从功能返回时,V8会从框架上弹出。

在Chrome Dev工具中调用堆栈

如您在上面的示例中所看到的,在每个函数调用上创建了一个帧,并在每个返回语句上删除(more about what is stored in the call stack you can read这里).

Everything else is allocated dynamically in a large unstructured piece of memory called theHeap.

Heap

Sometimes V8 doesn’t know at compile time how much memory an object variable will need. All the memory allocation for such data happens in the heap — unstructured region of memory. Objects on the heap live on after we exit the function that allocated the memory.

V8 has a built-in Garbage Collector (GC). Garbage collection is a form of memory management. It’s like a collector which attempts to release the memory occupied by objects that are no longer being used. In other words, when a variable loses all its references GC marks this memory as “unreachable” and releases it.

You can investigate heap by making a snapshot in Chrome Dev Tools.

Heap snapshot in Chrome Dev Tools (2.2 MB for a blank page!)

实例化的每个JavaScript对象都按其构造函数类别分组。括号的分组表示您无法直接调用的本机构造函数。如您所见,有很多(compiled code)(系统)实例,但也有一些传统的JavaScript对象数学,String,Array和so on.

浏览器运行时

So V8 can execute JavaScript according to the standard, synchronously, using a single call stack. But there is not much we can do with it. We need to render the UI. We need to handle user interactions with the UI. Moreover, we need to handle user interactions while making network requests. But how do we achieve concurrency when all our code is synchronous?It’s possible thanks to the browser engine.

The browser engine is responsible for rendering pages with HTML and CSS. In Chrome it’s called Blink. It’s a fork of网站这是一个布局,渲染和文档对象模型(DOM)库。眨眼是在C ++中实现的,并公开Web API,例如DOM元素和事件,XMLHttpRequest,拿来,setTimeout,setInterval等等,可以通过JavaScript访问.

让我们考虑以下示例settimeout(Ontimeout,0):

在Chrome Dev工具中调用超时的堆栈

如我们所见f1()f2()functions are pushed to the stack first and thenOntimeout被执行。

The key point is that we are registering a function to run at a later time. Whether it’s a user click or a timeout. Our asynchronous callback is executed by V8 only after the corresponding event is fired.

So how does the example above works?

Concurrency

紧随其后setTimeout执行功能 - 浏览器引擎位置setTimeout’s callback function into an事件表.It’s a data structure which maps registered callbacks to events, in our caseOntimeout函数到超时事件。

Once the timer expires, in our case immediately as we put 0 ms as the delay, the event is fired and theOntimeoutfunction is put in the事件队列(aka the callback queue or message queue or task queue). The event queue is a data structure which consists of callback functions (tasks) to be processed in the future.

And last but not least, the事件循环,一个不断运行的循环,检查呼叫堆栈是否为空。如果是这样,则执行了事件队列中的第一个添加回调,因此移至呼叫堆栈。

The processing of functions continues until the call stack is once again empty. Then the event loop will process the next callback in the event queue (if there is one).

const fn1 =()=> console.log('fn1')
const fn2 = () => console.log('fn2')
const callback =()=> console.log('timeout')
fn1()
settimeout(回调,1000)
fn2()
// 输出:
// FN1
// FN2
// timeout

ECMAScript 2015 introduced the concept of thejob queue(又称微任务队列)。这个队列充满了诺言resolve拒绝functions. Callbacks in the job queue have a higher priority of execution than callbacks in the event queue. Which means that the event loop will execute all of them one by one before any other callback in the event queue.

const fn1 =()=> console.log('fn1')
const fn2 = () => console.log('fn2')
const onTimeout = () => console.log('timeout')
const onResolve1 = () => console.log('resolved1')
const onResolve2 =()=> console.log('resolved2')
fn1()
settimeout(Ontimeout,0)
Promise.resolve()
.then(onResolve1)
.then(onResolve2)
fn2()// 输出:
// FN1
// FN2
// resolved1
// resolved2
// timeout

注意执行顺序onResolve1,onResolve2Ontimeoutcallbacks.

Blocking vs Non-Blocking

In simple terms, all the JavaScript code is consideredblocking.While V8 is busy with processing stack frames — the browser is stuck. The UI of your app is blocked. The user won’t be able to click, navigate, or scroll. Responses from your network requests won’t be processed until V8 finishes its work.

想象一下,您必须在浏览器中运行的程序中的图像解析。

const fn1 =()=> console.log('fn1')
const onResolve = () => console.log('resolved')
const parseimage =()=> { / *长期解析算法 * /}
fn1()
Promise.resolve().then(onResolve) // or any other Web API async fn
parceimage()

在上面的示例中,事件循环被阻止。它无法处理来自event/job queue因为call stack包含帧。

Web API使我们有可能写作non-blockingcode via asynchronous callbacks. When calling functions likesetTimeoutor拿来, we are delegating all the work to C++ native code which runs in a separate thread. As soon as the operation is completed the callback is put to事件队列. Meanwhile, V8 can continue further execution of JavaScript code.

使用此类并发模型,我们可以处理网络请求,用户与U​​I的交互等等,而无需阻止JavaScript执行线程。

OUTRO

Understanding what the JavaScript environment is composed of is crucial for every developer who wants to be able to solve complex tasks. Now we know how asynchronous JavaScript works, the role of the call stack, event loop, event queue and job queue in its concurrency model.

As you might have guessed there is a lot more going on behind V8 engine and browser engine. However, most of us simply need to have a basic understanding of all these concepts. Please, click the clap , if the article above was helpful for you.

获取中型应用betway娱乐官网

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Baidu