当前位置: 首页 > 科技观察

浏览器引擎编译执行原理你了解多少?

时间:2023-03-20 19:29:33 科技观察

本文转载自微信公众号《前端引力》,作者一川。转载本文请联系前端Gravity公众号。1浏览器引擎如何编译执行前面写的JS代码?本文将分析浏览器导致的JS代码编译,并结合实际开发经验,重新认识底层的编译分析机制,有助于理解前端开发跨终端的应用和一套多终端代码生成的底层逻辑。那么:Javascript代码是分几个阶段执行的?AST有什么用?2V8引擎我们知道编程语言分为编译型语言和解释型语言。它们各自的特点是:编译型语言:在代码执行过程中,预编译器直接将相应的代码转换成机器码。比如C++解释型语言:先把代码转成编译后的代码,再转成机器码,在运行时转换。例如:为了提高Python和Javascript的运行效率,很多浏览器厂商都在不断努力。在现代浏览器中,Chrome的v8引擎最为出色,引入了Java虚拟机和C++编译器等诸多技术。正因为如此,Node.js也是基于V8引擎开发的。那么v8引擎执行JS代码需要经过哪些阶段,如下:Parse阶段:v8引擎负责将JS代码转化为AST(抽象语法树)Ignition阶段:解释器将AST转化为字节码,解析并执行字节码,同时为下一阶段的优化编译提供所需的信息TurboFan阶段:编译器利用前一阶段收集的信息,将字节码优化为可执行的机器码Orinoco阶段:垃圾收集阶段,内存空间是程序中不再使用回收、编译、执行流程图AST在计算机科学中,抽象语法树(abstractsyntaxtree或缩写为AST),或句法树(syntaxtree),是对抽象的树状表示源代码的语法结构,特指编程语言源代码。在开发和生产中,我们经常会用到eslint、babel等工具,这些工具都与AST相关。v8引擎通过编译器将源代码解析成AST。常见的应用场景有:JS反编译、语法分析Babel编译ES6语法代码高亮关键字匹配代码压缩生成AST有两个关键:词法分析和语法分析语法分析:这个阶段会将源代码拆分成最小的、不可分割的词法单元,称为token,代码中的空格在JS中直接忽略。词法单元是独立的,即现阶段我们不关心每一行代码是如何组合的。句法分析:这个过程是将词法单元转化为元素逐级嵌套组成的树,以预测程序的语法结构,称为抽象语法树。将上一阶段生成的token列表转换为下图右侧所示的AST。根据这个数据结构,我们可以大致看出转换前源码的基本结构。简而言之,词法分析阶段就是将代码拆解成独立的、不可分割的token,语法分析阶段就是对拆分后的token进行解析,根据它们在整个代码上下文中的作用和联系来进行移除。额外的标记形成一个抽象语法树。浏览器暂不支持es6语法,需要转成es5语法。这个过程需要借助babel来实现。将es6源码解析成AST,然后将es6文法的抽象语法树转换成es5的抽象语法树,最后用它来生成es5的源码。Ignition生成字节码的阶段是将AST转换为字节码,但是之前的v8版本不会经过这个过程。最开始是直接通过AST转成机器码,后来的版本开始改进。将AST直接转换为机器码是有问题的,因为:直接转换会导致内存占用过大的问题。因为抽象语法树全部生成为机器码,而机器码比字节码占用内存多,一些JS的使用场景更适合使用解释器。解析成字节码,部分代码不需要解析成机器码,可以减少V8引擎占用的大量内存空间。将抽象语法树转换为字节码后,显着降低了内存占用,同时可以使用JIT编译器做进一步的优化。字节码是介于AST和机器码之间的代码。它需要转换成机器码才能执行。字节码可以理解为机器码的抽象。解释器得到AST后,根据需要进行解释执行,也就是说,如果一个函数没有被调用过,就不会解释执行。解释器创建一个调用栈来记录函数的调用过程。每次调用函数时,解释器都会将该函数添加到调用堆栈中。解释器将为添加的函数创建堆栈帧。这个栈帧是用来保存函数的局部变量和执行语句的,所以这个栈帧会被立即执行。如果正在执行的函数还调用了其他函数,新函数也会被加入调用栈并执行。一旦这个函数执行结束,相应的栈帧就会立即被销毁。查看调用栈有两种方式:调用函数console.log()打印到控制台,使用浏览器开发者工具断点调试。生成机器码如果发现一段代码被多次重复执行,生成的字节码和分析数据将被发送到TurboFan编译器,TurboFan编译器会根据分析数据生成优化的机器码。TurboFan编译器是一个JIT优化的编译器。TurboFan的编译线程和生成的字节码不会在同一个线程上,这样可以和Ignition解释器配合使用,不受对方的影响。TurboFan编译器使用Ignition解释器收集的分析数据,主要通过推测优化技术生成优化的机器代码以供执行。优化后的机器代码与缓存非常相似。当解释器再次遇到同样的内容时,可以直接执行优化后的机器码。当然,优化后的代码也有可能运行失败(比如函数参数类型改变),那么会再次反优化成字节码,交给解释器。3参考文章《Javascript核心原理精讲》《前端也要懂编译:AST 从入门到上手指南》《编译原理》4写在最后市面上主流JS引擎的编译过程大都大同小异。主要原因可能是在某些地方加入了特定的优化,但核心思想与v8大致相同。AST是一个比较重要的知识点。深入了解后,会帮助你自己实现前端工具。对此,大家可以通过多学习前端工具来提高自己的业务开发效率和编程能力。