🚀⚙️ JavaScript 可视化:JavaScript 引擎
JavaScript 很酷(别@我),但机器怎么才能真正理解你写的代码呢?作为 JavaScript 开发者,我们通常不需要自己处理编译器。然而,了解JavaScript 引擎的基础知识,看看它如何处理我们人性化的 JS 代码,并将其转换成机器能理解的代码,绝对是有益的!🥳
|注意:这篇文章主要基于 Node.js 和基于 Chromium 的浏览器使用的 V8 引擎。
HTML 解析器遇到script
带有源的标签。来自此源的代码会从网络、缓存或已安装的Service Worker加载。响应是作为字节流的请求脚本,字节流解码器会处理它!字节流解码器会在下载字节流时对其进行解码。
字节流解码器会从解码后的字节流中创建标记。例如,解码0066
为f
、 、0075
、u
、、、、、和后跟一个空格的 。好像你写的是006e
!这是 JavaScript 中的保留关键字,它会创建一个标记,并将其发送给解析器(以及预解析器,我在动图里没有介绍,但稍后会解释)。字节流的其余部分也会发生同样的情况。n
0063
c
0074
t
0069
i
006f
o
006e
n
function
引擎使用两个解析器:预解析器和解析器。为了减少网站加载时间,引擎会尽量避免解析那些不需要立即执行的代码。预解析器处理稍后可能用到的代码,而解析器处理那些立即需要的代码!如果某个函数只有在用户点击按钮后才会调用,那么就没有必要为了加载网站而立即编译这段代码。如果用户最终点击了按钮并需要这段代码,它才会被发送到解析器。
解析器根据从字节流解码器接收到的标记创建节点。通过这些节点,它创建了一棵抽象语法树(AST)。🌳
接下来,轮到解释器了!解释器会遍历抽象语法树 (AST),并根据 AST 包含的信息生成字节码。字节码生成完成后,AST 会被删除,从而清理内存空间。终于,我们得到了一些机器可以处理的东西!🎉
虽然字节码很快,但它还可以更快。字节码运行时会生成信息。它可以检测某些行为是否经常发生,以及所使用的数据类型。也许你已经调用过某个函数几十次了:是时候优化它,让它运行得更快了!🏃🏽♀️
字节码与生成的类型反馈一起被发送到优化编译器。优化编译器获取字节码和类型反馈,并据此生成高度优化的机器码。🚀
JavaScript 是一种动态类型语言,这意味着数据类型可以不断变化。如果 JavaScript 引擎每次都必须检查某个值的数据类型,那速度会非常慢。
为了减少解释代码所需的时间,优化的机器码仅处理引擎在运行字节码时遇到过的情况。如果我们反复使用某段返回相同数据类型的代码,可以简单地重复使用优化的机器码来加快速度。但是,由于 JavaScript 是动态类型的,因此同一段代码可能会突然返回不同类型的数据。如果发生这种情况,机器码就会被取消优化,引擎将回退到解释生成的字节码。
假设某个函数被调用了 100 次,到目前为止始终返回相同的值。它会假设第 101 次调用时也会返回相同的值。
假设我们有以下函数 sum,该函数(到目前为止)每次都以数值作为参数进行调用:
这将返回数字3
!下次我们调用它时,它会假定我们再次使用两个数值来调用它。
如果假设成立,则无需动态查找,只需重用优化后的机器码即可。否则,如果假设不正确,则将恢复为原始字节码,而不是优化后的机器码。
例如,下次调用它时,我们传递一个字符串而不是数字。由于 JavaScript 是动态类型的,所以我们可以这样做而不会出现任何错误!
这意味着该数字2
将被强制转换为字符串,并且函数将返回该字符串"12"
。它返回执行解释后的字节码并更新类型反馈。
希望这篇文章对你有用!😊 当然,引擎还有很多部分我没在这篇文章里讲到(JS 堆、调用栈等等),以后可能会讲到!如果你对 JavaScript 的内部机制感兴趣,我强烈建议你自己去研究一下。V8 是开源的,而且有很多很棒的文档介绍它的内部工作原理!🤖
V8 文档|| V8 Github || Chrome 大学 2018:脚本的生命周期
欢迎随时联系我!Twitter || Instagram || GitHub || LinkedIn
常见问题解答:我用 Keynote 制作动画并录屏,哈哈。欢迎将这篇博客翻译成你的语言,非常感谢!请保留原文链接,如果你翻译成功了,请告诉我!😊
文章来源:https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf