14 | 编译器和解释器:V8是如何执行一段JavaScript代码的?
14 | 编译器和解释器:V8是如何执行一段JavaScript代码的?
讲述:李兵
时长12:51大小11.73M
编译器和解释器
V8 是如何执行一段 JavaScript 代码的
1. 生成抽象语法树(AST)和执行上下文
2. 生成字节码
3. 执行代码
JavaScript 的性能优化
总结
思考时间
赞 56
提建议
精选留言(82)
- 不将就2019-09-05重复看之前的文章,受益良多,在此表示感谢! 不过有几个疑问,老师有空的解答下哈! 问题一: 渲染进程里的input标签上传图片,通过与浏览器主进程通信,主进程读取硬磁盘图片数据返回给渲染进程,渲染进程里的js发起ajax请求,是通过浏览器主进程去调用网络进程发起请求,还是渲染进程可以直接调用网络进程发起请求? 问题二: 请求长时间处于pending状态或者脚本执行死循环,这时刷新或前进后退页面不响应,刷新或前进后退页面是属于浏览器主进程的UI交互行为,为什么渲染进程里的js引擎执行会影响到主进程? 问题三: function fn(){ var a =10 function f1(){ console.log(a) }; function f2(){ console.log('f2') }; f2(); }; fn(); 我在函数f2里打断点,当执行到函数f2时,chrome里显示Closure:{a:10},如果把这个原因解释为在fn函数里会预扫描f1函数,那我现在把fn2函数和调用都注释了,现在执行fn函数时不产生Closure,为什么就不预扫描f1函数了?这是为什么?展开
作者回复: 第一个问题: xmlhttprequest 可以直接走网络进程,不需要浏览器进程介入 第二个问题: 因为前进或者后退也需要执行当前页面脚本啊,比如要执行beforeunload事件,执行的时候页面没响应了,所以前进后退也就失效了 第三个问题: 你把f2注释了,当执行fn函数时,照样会预扫描f1,照样会产生闭包,只不过当fn执行结束之后,闭包的内容没有外部引用,那么下次垃圾回收直接把比闭包的内容回收掉
共 8 条评论81 - 钟钟2019-09-08执行时间越长,执行效率越高。是因为更多的代码成为热点代码之后,转为了机器码来执行吗?
作者回复: 是的
共 8 条评论44 - Rapheal2019-09-09老师,编译的基本单位是一段JS代码(内敛JS)或者一个JS文件吗(还是以当前调用栈将要执行函数为单位)?
作者回复: 全局代码,或者函数 ! 比如下载完一个js文件,先编译这个js文件,但是js文件内定义的函数是不会编译的。 等调用到该函数的时候,Javascript引擎才会去编译该函数!
共 5 条评论42 - 舔命难违2020-03-04“V8 执行时间越久,执行效率越高”,难怪我电脑开机越久就越卡……共 8 条评论30
- Hurry2019-09-07从本文中明确的应该是在写代码的时候,如何让代码易于被 TurboFan 优化,减少反优化,老师提到的 hiddenClass 等我觉得大家还是有必要了解一下, 大家可以尝试使用 node 加选项 --trace-opt 跑代码体验一下 TurboFan 如何做优化,就会有很直观的感受 https://github.com/hjzheng/performance-test/blob/master/v8/addFunction.js20
- GY2019-09-27前面第7和第12讲,变量提升说js的执行过程,是有编译过程的,变量提升就发生在编译过程,经过编译后,会生成两部分内容,执行上下文和可执行代码,但是在这一讲中,却并没有编译过程,在AST生成后,解释器就开始执行生成字节码执行了,这几讲的内容有点互相冲突,那么详细的过程到底是怎样的呢 我在查看其它资料,出现了预编译这个名词,这个又怎么解释呢 希望能解答下展开
作者回复: 你可以把JavaScript的编译看成了部分: 第一部分从一段JavaScript代码编译到字节码,然后解释器解释执行字节码! 第二部分深度编译,将活跃的字节码编译成二进制,然后直接执行二进制。 无论哪个阶段都需要编译。
共 3 条评论11 - Bazinga2019-11-28总结说:V8 依据 JavaScript 代码生成 AST 和执行上下文,再基于 AST 生成字节码,然后通过解释器执行字节码,通过编译器来优化编译字节码。但是第二节生成字节码那一段 说:解释器 Ignition 就登场了,它会根据 AST 生成字节码,并解释执行字节码。还有即时编译(JIT)技术那张图片,看起来也是先生成字节码 再经过解释器 。 所以字节码是解释器生成的吗?我都看懵了,求解答。
作者回复: 流程是这样的: v8先生成ast! 然后ignition根据ast生成字节码。 在然后ignition解释执行字节码。 所以ignition生成了字节码并解释执行字节码。
共 2 条评论9 - westfall2019-10-23字节码最终也会转成机器码来执行的吧?因为最终都是cpu来执行,cpu只能执行机器码
作者回复: 是的
8 - Geek_Jamorx2019-09-05我想提一个问题,V8解析后的字节码或热节点的机器码是存在哪的,是以缓存的形式存储的么?和浏览器三级缓存原理的存储位置比如内存和磁盘有关系么? 最近面试有被问到,没答上来。。希望老师回答,十分感谢~共 10 条评论7
- 小兵2019-09-05避免大的内联脚本,因为在解析 HTML 的过程中,解析和编译也会占用主线程;这句话可以理解为解析HTML代码的时候需要解析内联代码,而放到js文件的时候不需要吗? 另外思考题应该是执行越久,热点代码越多,即时编译的作用越大。
作者回复: 只要是同步脚本都会阻塞,这里我可能没说清楚。 我的表达的以上是同步脚本尽量小,尽量能内联。 其它的尽量采用异步脚本,如使用aysnc和defer。
共 6 条评论7 - 李懂2019-09-05怎么都需要字节码文件,为啥,jsvaScript不像java一样先编译为字节码,这样执行效率不就高了么!
作者回复: 你可以认为WebAssembly就是,WebAssembly经过TuboFan处理下就能执行了
7 - Marvin2019-09-05我理解,V8执行越久,被编译成机器码的热点代码就越多,所以整体执行效率就越高。如果是这样的话,那么V8内存占用也会越来越多,会面临的问题会和
作者回复: 引入了字节码,就有弹性空间了,可以在内存和执行速度之间做调节。 相比之前的V8,将JS代码全部编译成字节码,这种模式就没有协商的空间了!
共 2 条评论6 - 阳仔2021-08-23面试被问到:js 在编译过程中,会做一定的优化,那么日常开发,应该怎么利用这个优化,提升代码质量共 1 条评论4
- Geek_panda2021-07-20老师还在吗,想请教2个问题 1. v8生成执行上下文是根据源码生成还是根据ast来生成呢? 2. 解释器执行字节码时是不是也需要将他转成机器码,如果是的话,那他是不是也会通过TurboFan编译器编译 @李兵 老师共 4 条评论2
- crown2020-05-15V8刚开始执行代码的时候, 都是通过ignition解释器来逐行解析字节码的, 这样性能会比较慢. 当执行一段时间过后, ignition可以捕获到经常被执行的到的字节码. 这些字节码就会被作为热代码交给turbofan编译成为机器码. 后续可以直接使用机器码, 而机器码的执行效率优于字节码. 当V8执行越久, 使用量高的字节码都被编译为机器码. 故V8执行越久, 效率越高2
- sugar2020-01-22老师您好,我曾想过不用babel typescript等的ast而是自己开发一个c++项目,引入v8利用他的ast来做一些代码转换工作,这样可以基于c的很多机制做更多多线程方面的优化。后发现这对于v8来说是不可能的,因为v8是一部分一部分解析js的,v8为什么采用这样的机制呢?另外这方面如果想自己动手拿v8做些事儿 老师有什么推荐的资料 或书籍可以看看吗?共 2 条评论2
- 七月有风2019-12-07老师,你好,node 的 JavaScript 引擎是 V8, ReactNative 和 Android webview 的 JavaScript 引擎是V8引擎吗?共 2 条评论2
- 刹那2019-10-22想到一个问题,可以把代码预先编译成字节码吗?这样浏览器下载了就能直接运行共 4 条评论2
- Geek_177f822019-09-16问一个基础的问题。希望老师解答。编译器编译后的二进制文件,与解析器解析后机器码是一个东西吗?共 2 条评论2
- Angus2019-09-05V8执行越久,被编译成机器码的热点就越多,这些机器码帮助字节码可以直接执行而不用再使用解释器逐行执行,这相当于浏览器缓存,提高了执行性能。这些生成的机器码也会带来内存占用升高的问题,这里应该会有一个权衡措施吧,根据已占用的内存权衡如何判定是热点并生成机器码保存。
作者回复: 是的,可以实现很多策略来权衡不同系统的情况
共 2 条评论2