[译]JavaScript引擎可视化

1,114 阅读3分钟

JavaScript很酷,但是计算机如何才能理解我们编写的代码?作为JavaScript开发人员,我们不必自己处理编译器。但是,一定要了解JavaScript引擎的基础知识,看看它是如何将我们编写的代码转换为机器可以理解的东西的!

注意:这边文章主要是针对基于V8引擎的Node和Chromium

HTML 解析器遇到 script 标签时,将会从网络,缓存,service worker中获取代码,随后将代码转换为字节流交由字节流解码器进行解码。

字节流解码器从解码的字节流中创建 token。

例如:

  • 0066 -> f
  • 0075 -> u
  • 006e -> n
  • 0063 -> c
  • 0074 -> t
  • 0069 -> i
  • 006f -> o
  • 006e -> n

解码获得 function 保留关键字,将创建 token 并发送至解析器,以及预解析器,其余字节流将按照这种模式继续解析。

引擎使用了预解析器和解析器。预解析仅仅检查是否有语法错误,这样可以避免解析器在解析时失败。

如果没有发现错误,则解析器根据获取的 token 创建节点,根据这些节点会创建一个 AST抽象语法树。

接下来interpreter遍历AST语法树,生成字节码,字节码生成完毕后将删除AST以节省内存空间。最后字节码交由计算器运行。

字节码执行时,将生成额外的信息用于检测某种行为是否经常发生,以及所使用的数据类型。也许你已经调用了数十次函数,是时候对其进行优化,使其运行的更快了。

字节码与生成的类型反馈一起发送到优化编译器,生成高度优化的机器码

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

引擎使用一种内联缓存的技术来进行优化,它将代码缓存到内存中,期待将来返回具有相同行为的相同值!假设某个函数被调用了100次,并且到目前为止一直返回相同的值,它将假设在第101次运行时也将返回此值。

假设我们有如下求和函数,我们总是以数值类型的参数来调用他

function sum(a, b) {
  return a + b;
}

sum(1, 2);

上述代码将返回数字3,在下次调用他时,他将假设我们再次使用这两个数字作为参数。

如果假设正确的话,则不需要进行动态查找,它可以使用缓存中的值作为返回结果。否则将代码从优化后的机器码转换为原始的字节码。

例如我们下次调用他时传递的参数是sum('1', 2), 数字2将被强制转换为字符串,函数将返回字符串 '12'。类型反馈将被更新。

V8 文档

原文链接: JavaScript Visualized: the JavaScript Engine