美文网首页
动图学 JavaScript 之: JS 引擎原理

动图学 JavaScript 之: JS 引擎原理

作者: Java架构师CAT | 来源:发表于2020-01-07 16:32 被阅读0次

前言

JS 实在是太酷了(认真脸),那你有没有想过机器是怎么解析 JS 代码的?作为一个 JS 开发者,一般我们不需要直接跟编译器打交道,但是如果可以了解其中的基本原理,相信会对以后的工作和学习都有帮助的!

本篇介绍的知识主要基于 Node.js 和基于 Chromium 的浏览器所用的 V8 引擎

生成抽象语法树

HTML 解析器在遇到script标签时,便会加载其中的代码。代码可能是从网络请求缓存或者Service Worker中加载的。由于代码是以字节流的形式响应回来的,所以当代码下载完成后就会交给字节流解码器

词法分析

生成抽象语法树的第一个阶段是分词 (tokenize),又叫词法分析

字节流解码器会先从代码字节流中创建令牌 (token)

注:令牌可以理解为语法上不可能再分的,最小的单个字符或字符串)。

如:0066解码为f,0075解码为u,0063解码为c,0074解码为t,0069解码为i,006f解码为o,006e解码为n同时后面跟一个空格。然后你就得到了关键字function!

每当一个令牌创建后,就会被传递给解析器(parser)。具体见下图:

语法分析

第二个阶段是解析(parse),也叫语法分析

引擎其实使用了两个解析器。一个是预解析器,一个是解析器

预解析器会先检查源码是否符合语法规则,如果不符合就直接抛出错误。这个提前检查机制可以提高解析器的效率。

如果没有错误,解析器便会根据传过来的令牌创建出抽象语法树 (Abstract Syntax Tree)并生成执行上下文(关于执行上下文的知识我们有机会再讲)

生成字节码

AST 被生成之后,接下来就要交给解释器(interpreter)了。解释器会遍历整个 AST,并生成字节码。当字节码生成后,AST 便会被删除以节省内存空间。最终我们得到了更贴近机器码字节码

这里的字节码是介于AST机器码之间的一种代码,它还是需要通过解释器将其转换为机器码后才能执行

执行代码

生成了字节码之后,就可以进入执行阶段了。执行阶段过程中引擎会做一些优化操作,一个是即时编译,一个是内联缓存

即时编译

尽管字节码很快,但是它还可以更快!解释器在逐条解释执行字节码时,会分析是否有某段代码被多次执行,这样的代码被称为热点代码

热点代码和生成的类型反馈 (type feedback)会被发送到一个称为优化编译器的东西中,然后由它转换为可以直接被电脑执行的机器码,这样在下次执行这段代码的时候就不需要再编译了,从而大大提升了代码的执行效率。

这种技术也被称为即时编译(JIT:Just In Time),而上面所说的优化编译器也叫JIT 编译器

内联缓存

JavaScript 是一种动态类型的语言,这意味着数据类型可以不断变化。如果 JS 引擎每次都要检查数据的类型,那速度将会非常慢。

所以引擎就使用了一种叫做内联缓存 (inline caching)的技术。它将代码缓存在内存中,以便将来可以针对相同的行为直接返回缓存的值。比如你有一个函数调用了 100 次,每次都返回同一个值,那么引擎就会假定在 101 次时也返回该值。

假设我们有一个求和函数sum,每次都接收两个数字:

上面的函数返回值为3!下次我们调用它时,引擎会假定我们还是传入两个数字类型的参数。

如果假设正确,就省去了动态查询阶段。引擎就可以直接使用存储在内存中的结果。否则,引擎会还原到原始字节码处解释执行,而不是使用优化过的机器码。

比如,下次我们要调用求和函数时,传入了一个字符串和一个数字,由于 JS 是动态类型的,所以不会报任何错误。

相关文章

网友评论

      本文标题:动图学 JavaScript 之: JS 引擎原理

      本文链接:https://www.haomeiwen.com/subject/ixxdactx.html