【这是我参与更文挑战的第 14 天,活动详情查看: 更文挑战”】
JavaScript是如何运行的
高级语言和低级语言
如果你随便找一个路人文,你会什么语言,那么他可能会回答英语、汉语、德语等等一系列语言。但是如果 你向一个程序员问出这个问题的时候,我想他的第一回答可能会是Java、PHP等折一系列的内容。在计算机领域我们把汉语、英语、Java, GO等都统称为语言,而把偏向于硬件的语言成为低级语言。我们可以使用低级语言来控制硬件的行为,把偏向于人类的语言,也就是 人类容易理解的语言叫高级语言,我们可以使用人类更容易阅读,更容易理解的高级语言来间接地控制硬件的行为。最低级的语言就是 机器语言,最高级的就是人类的语言。
高级语言易读写,简单抽象但执行能力差需要逐步转位跟低级的语言才能被硬件使用,越高级需要转换为时间也就越长,效率越低。越低级语言执行的速度越快, 但是缺少语言的便捷性就很难编写代码,并且 编写的代码容易出错,比如做内存管理、容易导致内存泄漏、难以追踪问题和坚决问题,并且 难以兼容众多的CPU平台。
本期的主角——JavaScript就是一门高级语言:
他借鉴了 c语言的基本语法,Java的内存管理和数据类型,scheme的函数式编程以及self的原型继承。
JavaScript引擎
既然JavaScript是一门高级余元 那么他在被计算机执行前就需要通过某种形式,将JS装换位计算机认识的语言并执行,这种程序就被称为JavaScript引擎。比如Chrome的V8引擎,webkit是使用的JavaScriptCore等很多就对了。
虽然解析器种类繁多但是 他们都有一定的相似之处:
都是将JS源码解析成抽象语法处AST在通过解释器将AST转换为字节码bytecode,字节码在动过编译器转换为不同的机器代码。由于不同的平台使用的机器代码有差异所以编译器会根据当前的平台编译出相应的机器代码。在不同的JS引擎中编译的表现或有一定的差异, 比如在我们接下来要讲的V8引擎。
V8引擎是如何编译和优化计算机代码的
首先, 先引用一下定义:
V8是Google的开源高性能JavaScript和WebAssembly引擎,用C ++编写。它用于Chrome和Node.js等。它实现ECMAScript和WebAssembly,并在Windows 7或更高版本,macOS 10.12+以及使用x64,IA-32,ARM或MIPS处理器的Linux系统上运行。 V8可以独立运行,也可以嵌入到任何C ++应用程序中。
V8主要做了一下工作:
- -编译和执行JS代码。
- 处理调用栈。
- 内存分配。
- 垃圾回收
大部分的JS引擎在解析JS时会用到 解析器、解释器、编译器方法我在上面提到了。
但是在早起的V8引擎中并没有解释器 但有俩编译器,他的流程是这个样子的:
JS由解析器解析后 生成AST语法树 之后由FULL-codegen直接只要AST编译成机器代码,中间不进行任何的代码转换。FULL-codegen又被称为基准编译器, 应为他生成的是一个基准的、没有被优化的代码这样做的好处是当你第一次执行JS代码时,直接使用的机器代码,没有只能够见到字节码产生,所以就不需要解释器,当代码运行一段时间后V8引擎收集了足够多的数据,来帮助另一个编译器crankshaft来优化JS代码,需要优化的代码有成型生成AST语法,然后crankshaft使用生成好的AST再生成优化后机器代码,来提升效率。 这样设计的初衷是减少抽象语法树到字节码的转换时间,提高浏览器中JS的运行效率。但这样的架构设计导致生成的机器代码较大,占用较大的内存空间。缺少中间码,无法实现优化策略。无法很好的支持新的js语法的新特性。于是乎 就有了新的V8引擎。 新V8引擎的执行机制 语法树的解析依旧报纸一致, 但是获得抽象语法树后加入了解释器lgnition语法树通过lgntition生成字节码bytecode,此时AST就会被清楚,释放空间。并且 生成的字节码会被直接执行 在执行的同时 还会被作为 基准执行模型,字节码更加简介的同时生成的字节码大小相当于等效的基准机器代码的25%~50%,在代码不断运行过程中解释器收集到了可以用来优化代码的信息,比如变量的类型, 那些函数执行的频率较高,这些信息就会被发送给编译器TurboFan,而新的编译器TurboFan会根据这些信息和字节码编译出进过优化后的机器代码