197

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

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

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

4

6 回答 6

345

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


铬:V8 引擎

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

资源


更新 - 2015 年 3 月 19 日

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

  1. 脚本流

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

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

  1. 代码缓存

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

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


Opera : 卡拉坎引擎

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

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

资源


火狐:蜘蛛猴引擎

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

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

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

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

编辑:有人指出,Mozilla 开发人员 Boris Zbarsky 表示 Gecko 尚未缓存已编译的脚本。取自这个 SO answer


Safari : JavaScriptCore/SquirelFish 引擎

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

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

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

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


IE : 脉轮引擎

此字段中没有关于 IE9 的 JavaScript 引擎 (Chakra) 的当前信息。如果有人知道什么,请发表评论。

这是相当非官方的,但对于 IE 的旧引擎实现,Eric Lippert(JScript 的 MS 开发人员)博客回复中表示:

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

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

于 2012-02-13T13:27:47.700 回答
12

正如另一个答案中提到的,Opera 做到了。(来源

Firefox(SpiderMonkey 引擎)不缓存字节码。(来源

WebKit(Safari、Konqueror)不缓存字节码。(来源

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

于 2012-02-13T10:34:08.043 回答
3

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

于 2012-02-12T18:40:13.620 回答
2

Google Dart通过“快照”明确解决这个问题毫无价值——目标是通过加载预解析的代码版本来加快初始化和加载时间。

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

于 2012-02-20T19:26:32.643 回答
0

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

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

于 2009-07-08T08:59:06.927 回答
0

浏览器肯定会使用缓存,但是是的,每次页面刷新时浏览器都会解析 JavaScript。因为每当浏览器加载页面时,它都会创建 2 棵树 1.Content 树和 2.render 树。

此渲染树包含有关 dom 元素的视觉布局的信息。因此,每当页面加载时,都会解析 javascript,并且 javascript 的任何动态更改都会像定位 dom 元素、显示/隐藏元素、添加/删除元素将导致浏览器重新创建渲染树。但现代浏览器如FF和chrome处理方式略有不同,它们有增量渲染的概念,所以每当上面提到的js发生动态变化时,只会导致那些元素重新渲染和重绘。

于 2012-02-13T10:23:20.880 回答