加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

V8是如何快速地解析JavaScript延迟解析

发布时间:2019-05-29 11:55:20 所属栏目:建站 来源:Web前端程序员
导读:解析是将源代码转换成一个中间表示形式供编译器使用的步骤(在V8中,是字节码编译器Ignition)。解析和编译发生在web页面启动的关键路径上,在启动期间,并不是所有提供给浏览器的函数都需要被调用。尽管开发人员可以使用异步和延迟脚本来延迟这些代码的加载

尽管如此,但我们现在不再需要重新解析内部函数,而且由于解析器变得更快,通过optimize-js获得的性能改进也大大降低。实际上,v7.5的默认配置已经比运行在v6.1上的优化版本快得多。即使在v7.5中,对于启动期间需要的代码,少量使用PIFEs仍然很有用: 我们避免了预解析,因为我们很早就知道会需要这个函数。

尽管如此,但我们现在不再需要重新解析内部函数,而且由于解析器变得更快,通过optimize-js获得的性能改进也大大降低。实际上,v7.5的默认配置已经比运行在v6.1上的优化版本快得多。即使在v7.5中,对于启动期间需要的代码,少量使用PIFEs仍然很有用: 我们避免了预解析,因为我们很早就知道会需要这个函数。

optimize-js基准测试结果并不能准确地反映实际情况。脚本是同步加载的,整个解析+编译时间都被计入加载时间。在实际环境中,你可能会使用<script>标记来加载脚本。这使得Chrome的预加载器能够在脚本被计算之前就发现它,并在不阻塞主线程的情况下下载、解析和编译该脚本。我们决定急切地编译的所有东西都是在主线程之外自动编译的,这样就会确保计入启动时间的值最小化。使用非主线程脚本编译来运行会放大使用PIFEs的影响。

但是,这样做仍然有成本,特别是内存成本,所以急切地编译所有东西并不是一个好主意:

V8是如何快速地解析JavaScript: 延迟解析

急切地编译所有JavaScript会付出巨大的内存代价。

虽然在启动期间为需要的函数添加圆括号是一个好主意(例如,基于配置的启动),但是使用像optimize-js这样的包来应用简单的静态启发式并不是一个好主意。例如,它假设一个函数在启动期间被调用,如果它是一个函数调用的参数。但是,如果这样一个函数实现了一个只需要很长时间的完整模块,那么最终会编译太多。过于急切地编译对性能没有好处: 没有延迟编译的V8会显著地降低加载时间。此外,当UglifyJS和其它minifiers(最小化器)从不是IIFEs的PIFEs中删除括号时,也就删除了本可以应用于通用模块定义样式模块的有用提示,这样一来,optimize-js的一些好处就带来了问题。这可能是minifiers应该修复的一个问题,以便在急切地编译PIFEs的浏览器上获得最大的性能。

结论

延迟解析加快了启动速度,并减少了应用程序的内存开销,这些应用程序带有的代码比它们需要的多。能够正确地跟踪预解析中的变量声明和引用对于正确(根据规范)快速地进行预解析是必要的。在预解析器中分配变量还允许我们序列化变量分配信息,以便后续在解析器中使用,这样我们就可以完全避免必须重新预解析内部函数,避免深度嵌套函数的非线性解析行为。

解析器可以识别的PIFEs避免了启动过程中立即需要的代码的初始预解析的开销。谨慎地使用配置文件导向的PIFEs,或使用打包器,可以提供一个有用的冷启动减速带。但是,应该避免为了触发这种启发式而将函数封装在括号中这样的没必要的操作,因为这会导致更多的代码被急切地编译,从而导致更差的启动性能和更大的内存使用量。

1.出于内存方面的原因,如果V8在一段时间内没有被使用,它就会刷新字节码。如果代码运行结束后,稍后又需要重新运行,我们将重新解析并编译它。由于我们允许变量元数据在编译期间死亡,这就需要在延迟重新编译的过程中重解析内部函数。此时,我们就需要为代码的内部函数重新创建元数据,因此就不需要再一次重新预解析代码内部函数中的内部函数。??(https://v8.dev/blog/preparser#fnref1 )

2.PIFEs也可以看作是基于配置文件通知的的函数表达式。??(https://v8.dev/blog/preparser#fnref2 )

英文原文:https://v8.dev/blog/preparser

译者:天天向上

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读