V8是一个虚拟机,作为js的执行环境,它可以模拟cpu,堆栈,寄存器等

高级语言的处理

233820555-2c654b4a-7c51-4ac1-a802-1b4e29df2bf9

233820562-3570cf51-2122-4517-acb4-fe4aead0e281

V8的处理

融合解释执行和编译执行(Just In Time):准备执行环境→解析源码生成AST和作用域→生成字节码→解释字节码输出结果→监控热点代码→热点代码编译为机器码执行→反优化生成的机器码(抛弃当前优化的二进制代码,回退使用字节码解释执行)
233820591-45b1bab6-2809-40f8-991a-182539c5dae0

字节码

V8早期并没有使用字节码,而是将JavaScript代码直接编译成机器码。为了提升性能,运行时将二进制存在内存中,并在浏览器退出时,缓存编译好的二进制到硬盘里。但是二进制实在是太大了,这种空间换时间的方法逐渐不可行,所以引入了字节码。

惰性解析

基于性能原因(速度慢,消耗内存),V8并不会一次性将所有的JavaScript代码全部解析为字节码。

所有主流的 JavaScript 虚拟机都实现了惰性解析。所谓惰性解析,是指解析器在执行过程中,如遇到函数声明,那么会跳过函数内部代码,而仅仅生成顶层代码的AST和字节码。

特殊情况:闭包

虽然采取了惰性解析,不会解析和执行父级函数中的子级函数,但是 V8 还是需要判断子级函数是否引用了 foo 函数中的变量,因为在正常流程中父级函数执行完毕就要销毁,这是矛盾的。负责处理这一部分的模块叫预解析器。

预解析器

预解析器的作用一个是检查函数语法错误,另一个就是检查函数内部是否引用外部变量,如果引用了,预解析器会将栈中的变量移至堆中,使用时直接使用堆中的引用。

隐藏类

V8为每个对象创建了一个隐藏类,该隐藏类保存了属性的偏移值,拿到偏移值究竟可以直接去内存中获取值。但是如果在这基础上添加或删除属性,V8会重建隐藏类。

async/await

async/await就是 Promise 和生成器应用,往底层说,就是微任务和协程应用。

协程

一个比线程颗粒度更小的任务进程,他跑在线程上,一个线程可以有多个协程,但是最多只可可以同时跑一个协程。

❤️ 转载文章请注明出处,谢谢!❤️