浏览器会在每个页面加载时解析 javascript 吗?

IT技术 javascript browser-cache javascript-engine
2021-01-21 04:18:09

浏览器(IE 和 Firefox)是否在每次页面刷新时解析链接的 javascript 文件?

他们可以缓存文件,所以我猜他们不会每次都尝试下载它们,但由于每个页面本质上都是独立的,我希望他们拆除所有旧代码并重新解析它。

这是低效的,虽然完全可以理解,但我想知道现代浏览器是否足够聪明来避免站点内的解析步骤。我正在考虑网站使用 javascript 库的情况,如 ExtJS 或 jQuery 等。

6个回答

这些是我能够挖掘的细节。首先值得注意的是,尽管 JavaScript 通常被认为是在 VM 上解释和运行的,但现代解释器并非如此,它们倾向于将源代码直接编译为机器代码(IE 除外)。


铬:V8引擎

V8 有一个编译缓存。这使用源代码的哈希存储编译后的 JavaScript,最多可进行 5 次垃圾回收。这意味着两个相同的源代码将在内存中共享一个缓存条目,无论它们是如何包含的。重新加载页面时不会清除此缓存。

来源


更新 - 19/03/2015

Chrome 团队已经发布了有关他们的 JavaScript 流和缓存新技术的详细信息

  1. 脚本流

脚本流优化了 JavaScript 文件的解析。[...]

从版本 41 开始,Chrome 会在下载开始后立即在单独的线程上解析异步和延迟脚本。这意味着解析可以在下载完成后的几毫秒内完成,并导致页面加载速度提高 10%。

  1. 代码缓存

通常,V8 引擎会在每次访问时编译页面的 JavaScript,将其转换为处理器可以理解的指令。一旦用户离开页面,这个编译的代码就会被丢弃,因为编译的代码高度依赖于编译时机器的状态和上下文。

Chrome 42 引入了一种先进的技术,将编译后的代码存储在本地副本,这样当用户返回页面时,下载、解析和编译步骤都可以跳过。在所有页面加载中,这使 Chrome 可以避免大约 40% 的编译时间,并为移动设备节省宝贵的电池电量。


歌剧:卡拉坎引擎

实际上,这意味着每当将要编译的脚本程序的源代码与最近编译的其他程序的源代码相同时,我们都会重用编译器的先前输出并完全跳过编译步骤。这种缓存在典型的浏览场景中非常有效,在这种情况下,从同一站点加载一页又一页,例如来自新闻服务的不同新闻文章,因为每个页面通常加载相同的、有时非常大的脚本库。

因此 JavaScript 在页面重新加载时被缓存,对同一脚本的两个请求不会导致重新编译。

来源


火狐:SpiderMonkey 引擎

SpiderMonkey 使用NanojitJIT 编译器作为其原生后端。编译机器码的过程可以在这里看到简而言之,它似乎在加载脚本时重新编译它们。但是,如果我们仔细查看内部结构,Nanojit我们会发现jstracer用于跟踪编译的更高级别的 monitor可以在编译期间过渡到三个阶段,从而为Nanojit

跟踪监视器的初始状态是正在监视。这意味着蜘蛛猴正在解释字节码。每次spidermonkey 解释一个向后跳转字节码时,监视器都会记录跳转目标程序计数器(PC) 值被跳转到的次数。此数字称为 PC 的命中计数。如果特定 PC 的命中计数达到阈值,则该目标被认为是热的。

当监视器确定目标 PC 很热时,它会在片段的哈希表中查找是否存在包含该目标 PC 的本机代码的片段。如果找到这样的片段,它就会转换到执行模式。否则它会转换到录制模式。

这意味着对于hot代码片段,本地代码会被缓存。这意味着不需要重新编译。不清楚这些散列的本机部分是否在页面刷新之间保留。但我会假设它们是。如果有人能为此找到支持证据,那就太好了。

编辑:它已经指出,Mozilla开发鲍里斯Zbarsky曾表示,壁虎不缓存编译脚本取自this SO answer


Safari : JavaScriptCore/SquirelFish 引擎

我认为这个实现的最佳答案已经由其他人给出了

我们目前不缓存字节码(或本机代码)。这是
我们考虑过的一个选项,然而,目前,代码生成是
JS 执行时间的一个微不足道的部分 (< 2%),所以我们目前不追求
这个。

这是由Safari 的首席开发人员Maciej Stachowiak编写的所以我认为我们可以认为这是真的。

我找不到任何其他信息,但您可以在此处阅读有关最新SquirrelFish Extreme引擎速度改进的更多信息,或者如果您喜欢冒险,请在此处浏览源代码


IE : 脉轮引擎

该领域目前没有关于 IE9 的 JavaScript 引擎 (Chakra) 的信息。如果有人知道任何事情,请发表评论。

这是相当非正式的,但对于IE的旧的引擎实现,埃里克利珀(JScript中的MS开发商)在博客中回应称这里是:

JScript Classic 就像一种编译语言,在任何 JScript Classic 程序运行之前,我们都会对代码进行全面的语法检查,生成完整的解析树,并生成字节码。然后我们通过字节码解释器运行字节码。从这个意义上说,JScript 与 Java 一样“已编译”。不同之处在于 JScript 不允许您保留或检查我们的专有字节码此外,字节码比 JVM 字节码高级得多——JScript Classic 字节码语言只不过是解析树的线性化,而 JVM 字节码显然旨在在低级堆栈机器上运行。

这表明字节码不会以任何方式持久化,因此不会缓存字节码。

谢谢,我在旅行中看到了这一点,但找不到任何其他支持证据。我会用它编辑答案。
2021-03-19 04:18:09
请注意,关于 IE 的说法是在 2003 年说的:IE9 的 JS 引擎首次发布是在 2011 年的 IE9 中。
2021-03-25 04:18:09
此外,Opera 缓存 JS 字节码不仅仅是重新加载。(但是,生成的机器代码不会被缓存)。
2021-04-03 04:18:09
+1,优秀的文章。但是,关于 Firefox,请参阅此 StackOverflow 问题,Mozilla 开发人员 Boris Zbarsky 解释说 Gecko 目前不这样做。
2021-04-05 04:18:09
@Jivings 以上为出处。(我是 Carakan 团队的成员之一。)
2021-04-05 04:18:09

Opera 做到了,正如另一个答案中所述。来源

火狐(SpiderMonkey的引擎)则没有缓存的字节码。来源

WebKit的(Safari浏览器,Konqueror中)确实缓存字节码。来源

我不确定 IE[6/7/8] 或 V8 (Chrome),我认为 IE 可能会做某种缓存,而 V8 可能不会。IE 是封闭源代码,所以我不确定,但在 V8 中缓存“编译”代码可能没有意义,因为它们直接编译为机器代码。

字节码已被 IE 用于……永远。这在 IE8 中并不是什么新鲜事。只是给定一个解释器,解释器的性能比解析时间慢得多,这完全无关紧要。IE9 有一个全新的(从头开始的)JS 引擎,所以两者之间没有任何关系。
2021-03-16 04:18:09
@gsnedders:我不确定 IE8 在技术上不能做到这一点,它似乎也编译为字节码(不是官方的而是关闭的),所以没有技术上的理由不缓存它。IE9 似乎添加了一个 JIT 来编译为本机代码。
2021-03-24 04:18:09
IE6-8 几乎肯定不会。IE9 可能,但我没有任何证据。编译后的 JS 可能不会缓存在任何地方,因为它通常非常大。
2021-04-07 04:18:09

据我所知,只有 Opera 缓存解析的 JavaScript。请参阅此处的“缓存编译程序”部分

谢谢,您也有其他浏览器系列的更多详细信息吗?
2021-03-18 04:18:09

这是值得什么,谷歌飞dart通过“快照”明确铲球这个问题-我们的目标是通过加载代码的preparsed版本,以加快初始化和加载时间。

InfoQ 有一篇很好的文章 @ http://www.infoq.com/articles/google-dart

我认为正确的答案是“并非总是如此”。据我了解,浏览器和服务器都在确定缓存内容方面发挥作用。如果您真的需要每次都重新加载文件,那么我认为您应该能够从 Apache 内部进行配置(例如)。当然,我认为用户的浏览器可以配置为忽略该设置,但这可能不太可能。

所以我想在大多数实际情况下,javascript 文件本身被缓存,但每次页面加载时都会动态重新解释。