# 可视化的JavaScript —— (四)JS引擎

【四】JavaScript Visualized: the JavaScript Engine (opens new window)

JavaScript很酷,但是机器如何才能真正理解您编写的代码?作为JavaScript开发人员,我们通常不必自己处理编译器。但是,一定要了解JavaScript引擎的基础知识,接下来我们来看看它如何处理我们人类友好的JS代码,并将其转变为机器可以理解的东西!

注意:这篇文章主要基于Node.jsChromium的浏览器使用的V8引擎。

HTML解析器遇到带来源的script标签。来自此源的代码便从网络,缓存或已安装的服务工作程序中加载。字节流解码器会处理请求脚本的响应字节流,字节流一边加载,一边被该字节流解码器解码。

pv4y4w0doztvmp8ei0ki

字节流解码器从解码后的字节流中创建令牌。例如,0066解码到f0075u006en0063c0074t0069i006fo006en最后跟一个空格。就好像是你书写function一样!这是JavaScript中的保留关键字,创建令牌并将其发送到解析器(和pre-parser,我没有在gif中介绍,但稍后会进行解释)。其余字节流也会发生同样的情况。

bic727jhzu0i8uep8v0k

引擎使用两个解析器:pre-parserparser。为了减少加载网站所需的时间,引擎尝试避免立即解析不必要的代码。预解析器处理以后可能使用的代码,而解析器则处理立即需要的代码!如果某个特定函数仅在用户单击按钮后才被调用,则不必在加载网站时立即编译此代码。如果用户最终最终单击该按钮并需要该段代码,它将被发送到解析器。

解析器根据从字节流解码器接收的令牌创建节点。使用这些节点,它会创建一个抽象语法树或AST

sgr7ih6t7zm2ek28rtg6

接下来,该解释器登场了!解释器遍历AST,并根据AST包含的信息生成字节码。字节码生成完毕后,将删除AST,以清除内存空间。最后,我们拥有一台机器可以使用的东西!

i5f0vmcjnkhireehicyn

尽管字节码运行很快,但是可以更快。随着此字节码的运行,会生成相关信息。它可以检测某些行为是否经常发生,以及所使用的数据类型。也许您已经调用了数十次函数:那么是时候对其进行优化,使其运行得更快了!

字节码与生成的类型反馈一起被发送到优化编译器。优化编译器获取字节码和类型反馈,并从中生成高度优化的机器码。

ongt4qftovd82sp2vihk

JavaScript是一种动态类型化的语言,这意味着数据类型可以不断变化。如果JavaScript引擎每次必须检查某个值具有哪种数据类型,那将非常慢。

为了减少解释代码所花费的时间,优化的机器代码仅处理引擎在运行字节码时曾见过的情况。如果我们反复使用某一段代码,一遍又一遍地返回相同的数据类型,则可以简单地重新使用经过优化的机器代码以加快处理速度。但是,由于JavaScript是动态类型的,因此可能发生相同的代码突然返回不同类型的数据的情况。如果发生这种情况,则会对机器代码进行反向优化,并且引擎会退回到解释生成的字节码。

假设某个函数被调用了100次,并且到目前为止一直返回相同的值。可以假定它也会在您第101次调用它时返回该值。

假设我们有以下函数sum,到目前为止,每次都使用数值作为参数来调用它:

image

这将返回数字3!下次调用它时,它将假定我们再次使用两个数值调用它。

如果是这样,则不需要动态查找,并且可以重新使用经过优化的机器代码。否则,如果假设不正确,它将恢复为原始字节码,而不是优化的机器码。

例如,下一次调用它时,我们传递的是字符串而不是数字。由于JavaScript是动态类型的,因此我们可以做到这一点而没有任何错误!

image

这意味着该数字2将被强制转换为字符串,而该函数将返回该字符串 "12"。返回执行解释的字节码并更新类型反馈。

希望这篇文章对您有用!😊当然,我在这篇文章中没有涉及引擎的许多部分(JS堆,调用堆栈等),我以后可能会涉及!如果您对JavaScript的内部结构感兴趣,我绝对鼓励您自己开始做一些研究,V8是开源的,并且有一些很好的文档说明了它的幕后工作方式!🤖

【完】

上次更新: 1/8/2023, 9:08:35 AM