JavaScript 引擎和 Just-in-Time 编译概念,Hot Function 的简单介绍

简介: JavaScript 引擎本身也是一种软件,它将您华丽的 JavaScript 代码行转换为我们的机器可执行的二进制代码。

image.png

有了如此严格的规则,静态类型语言可以具有更高的学习曲线。在尝试编写一个简单的程序之前,您必须更多地了解它的规则和类型。


然而,从编译器的角度来看,静态类型语言允许更快的性能。预先,当编译器开始将代码转换为可执行的机器代码二进制时,该语言为编译器提供了大量有关源代码的信息。


另一方面,像 JavaScript 这样的动态类型语言很少向编译器提供有关其类型的信息。这为编译器在生成机器代码之前创建了另一层工作,使其执行速度比静态编写语言的编译慢。


But fear not, this is where Just-In-Time compilation comes in!

最初开发 JavaScript 时,它旨在编写少量用于增强网页的脚本。随着开发人员开始构建和使用更多 JavaScript 框架和库,以及发出 AJAX 请求,对更好、更快性能的需求不断增长。


当 Chrome 于 2008 年推出时,谷歌还首次发布了其 V8 引擎,这是现代 JavaScript 引擎中的第一个。 V8 的主要特性之一是即时编译 - Just-In-Time compilation。


在 Ahead-of-Time 编译中,编译过程必须在系统运行可执行机器代码之前完成。有了 Just-In-Time compilation 这一新特性,V8引擎会根据需要编译源代码,在执行编译过程生成的机器码时收集类型信息,然后根据执行过程收集的信息重新编译源代码。两个进程之间的来回加快了执行过程的性能。


为了让 JavaScript 在动态类型的情况下仍能以最快的速度运行,JavaScript 引擎有一些巧妙的技巧。


像大多数现代 JavaScript 引擎一样,V8 有两个编译器:基线 (baseline)编译器和优化编译器。


当 V8 编译你的 JavaScript 代码时,它的解析器会生成一种叫做抽象语法树的东西。Ignition,V8 的基线编译器或解释器,从这个语法树生成字节码。 Ignition 忠实于它的即时编译特性,它编译 JavaScript 代码,运行它,编译它,运行它,来回,一遍又一遍。


在运行时,字节码被分析,引擎识别可以重新编译以获得最佳性能的部分(“热函数”),将该代码发送到 TurboFan,它是 V8 的优化编译器。正是因为即时编译,引擎才能够因为即时编译而识别这些所谓的“热功能”。

image.png

The + operator and V8 optimization

在她的精彩演讲 JavaScript 引擎中,V8 工程师 Franziska Hinkelmann 使用 + 运算符来解释 V8 的优化是如何工作的。


乍一看,加法运算符可能看起来很简单,任何编译器都可以编译和执行。 但是,如果您查看 Ecma 规范,在程序实际添加任何内容之前,引擎实际上需要执行很多步骤:

image.png

这些步骤中的每一步都在调用其他函数,而这些函数又可能调用其他函数,依此类推。所有引擎都必须遵循这些 Ecma 规范,因此 JavaScript 不仅仅是无法无天的。


因此,当您的程序有一个将两个整数相加的函数时,当您第一次调用该函数时,JavaScript 引擎会费力地完成这些步骤中的每一步,最终将您的两个整数相加。当它通过 JIT 过程(编译、运行、编译、运行、编译等)时,它意识到你的函数很热,很热,很热,因为你一直在调用它。从引擎在运行时收集的信息,它也意识到这个特定函数使用的数据类型只是整数。有了这些信息,V8 将您的代码发送到 TurboFan,它的优化器编译器,它为您的函数生成更好的机器代码。下次您再次调用该函数时,它会跳过冗长的 Ecma 步骤,您的函数将运行得更快。


但是当您决定在调用该函数时连接一些字符串而不是添加两个整数时会发生什么? V8 将该函数抛出到去优化器,将其发送回 Ignition,然后 Igntion 再次执行那些 Ecma 指定的步骤来运行该函数。

相关文章
|
27天前
|
机器学习/深度学习 自然语言处理 JavaScript
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
在信息论、机器学习和统计学领域中,KL散度(Kullback-Leibler散度)是量化概率分布差异的关键概念。本文深入探讨了KL散度及其相关概念,包括Jensen-Shannon散度和Renyi散度。KL散度用于衡量两个概率分布之间的差异,而Jensen-Shannon散度则提供了一种对称的度量方式。Renyi散度通过可调参数α,提供了更灵活的散度度量。这些概念不仅在理论研究中至关重要,在实际应用中也广泛用于数据压缩、变分自编码器、强化学习等领域。通过分析电子商务中的数据漂移实例,展示了这些散度指标在捕捉数据分布变化方面的独特优势,为企业提供了数据驱动的决策支持。
47 2
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
|
5月前
|
JavaScript 前端开发 开发者
JavaScript的变量提升是一种编译阶段的行为,它将`var`声明的变量和函数声明移至作用域顶部。
【6月更文挑战第27天】JavaScript的变量提升是一种编译阶段的行为,它将`var`声明的变量和函数声明移至作用域顶部。变量默认值为`undefined`,函数则整体提升。`let`和`const`不在提升范围内,存在暂时性死区。现代实践推荐明确声明位置以减少误解。
43 2
|
23天前
|
设计模式 JavaScript 前端开发
探索JavaScript中的闭包:从基础概念到实际应用
在本文中,我们将深入探讨JavaScript中的一个重要概念——闭包。闭包是一种强大的编程工具,它允许函数记住并访问其所在作用域的变量,即使该函数在其作用域之外被调用。通过详细解析闭包的定义、创建方法以及实际应用场景,本文旨在帮助读者不仅理解闭包的理论概念,还能在实际开发中灵活运用这一技巧。
|
25天前
|
存储 JavaScript 前端开发
JavaScript 对象的概念
JavaScript 对象的概念
34 4
|
23天前
|
缓存 JavaScript 前端开发
深入了解JavaScript的闭包:概念与应用
【10月更文挑战第8天】深入了解JavaScript的闭包:概念与应用
|
19天前
|
前端开发 JavaScript 程序员
【从前端入门到全栈】Node.js 之核心概念
【从前端入门到全栈】Node.js 之核心概念
|
22天前
|
JavaScript 前端开发 Java
JS引擎V8
【10月更文挑战第9天】
24 0
|
23天前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:概念与应用
【10月更文挑战第8天】深入理解JavaScript中的闭包:概念与应用
|
2月前
|
自然语言处理 JavaScript 前端开发
探索JavaScript中的闭包:从基础概念到实际应用
本文深入探讨了JavaScript中闭包的概念,从定义、作用域链和实际应用等方面进行了详细阐述。通过生动的比喻和实例代码,帮助读者理解闭包在函数执行上下文中的重要性,以及如何在实际开发中有效利用闭包解决复杂问题。同时,文章也指出了过度使用闭包可能导致的潜在问题,并给出了相应的优化建议。
|
2月前
|
JavaScript 前端开发
一个js里可以有多少个async function,如何用最少的async function实现多个异步操作
在 JavaScript 中,可以通过多种方法实现多个异步操作并减少 `async` 函数的数量。