每次页面刷新时,浏览器(IE 和 Firefox)是否解析链接的 javascript 文件?
他们可以缓存文件,所以我猜他们不会每次都尝试下载它们,但由于每个页面本质上是独立的,我希望他们能够拆除任何旧代码并重新解析它。
这是低效的,虽然完全可以理解,但我想知道现代浏览器是否足够聪明,可以避免站点内的解析步骤。我正在考虑网站使用 javascript 库(如 ExtJS 或 jQuery 等)的情况。
每次页面刷新时,浏览器(IE 和 Firefox)是否解析链接的 javascript 文件?
他们可以缓存文件,所以我猜他们不会每次都尝试下载它们,但由于每个页面本质上是独立的,我希望他们能够拆除任何旧代码并重新解析它。
这是低效的,虽然完全可以理解,但我想知道现代浏览器是否足够聪明,可以避免站点内的解析步骤。我正在考虑网站使用 javascript 库(如 ExtJS 或 jQuery 等)的情况。
这些是我能够挖掘的细节。首先值得注意的是,虽然 JavaScript 通常被认为是在 VM 上解释和运行,但现代解释器并非如此,它们倾向于将源代码直接编译成机器代码(IE 除外)。
铬:V8 引擎
V8 有一个编译缓存。这使用源的哈希存储已编译的 JavaScript,最多可用于 5 个垃圾收集。这意味着两个相同的源代码将在内存中共享一个缓存条目,无论它们是如何包含的。重新加载页面时不会清除此缓存。
更新 - 2015 年 3 月 19 日
Chrome 团队已经发布了有关他们的 JavaScript 流和缓存新技术的详细信息。
脚本流优化 JavaScript 文件的解析。[...]
从版本 41 开始,Chrome 会在下载开始后立即在单独的线程上解析异步和延迟脚本。这意味着解析可以在下载完成后的几毫秒内完成,从而使页面加载速度提高 10%。
通常,V8 引擎会在每次访问时编译页面的 JavaScript,将其转换为处理器可以理解的指令。一旦用户离开页面,编译后的代码就会被丢弃,因为编译后的代码高度依赖于编译时机器的状态和上下文。
Chrome 42 引入了一种存储已编译代码的本地副本的高级技术,因此当用户返回页面时,可以跳过下载、解析和编译步骤。在所有页面加载中,这使 Chrome 可以避免大约 40% 的编译时间,并节省移动设备上宝贵的电池电量。
Opera : 卡拉坎引擎
在实践中,这意味着每当一个脚本程序即将被编译,其源代码与最近编译的其他程序的源代码相同时,我们重用编译器的先前输出并完全跳过编译步骤。这种缓存在典型的浏览场景中非常有效,因为每个页面通常加载相同的,有时非常大的脚本库,从同一站点加载页面后的页面,例如来自新闻服务的不同新闻文章。
因此 JavaScript 在页面重新加载时被缓存,对同一脚本的两个请求不会导致重新编译。
火狐:蜘蛛猴引擎
SpiderMonkey 使用Nanojit
JIT 编译器作为其原生后端。编译机器码的过程可以看这里。简而言之,它似乎在加载脚本时重新编译脚本。但是,如果我们仔细查看内部结构,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 字节码显然旨在在低级堆栈机器上运行。
这表明字节码不会以任何方式持续存在,因此字节码不会被缓存。
据我所知,只有 Opera 缓存已解析的 JavaScript。请参阅此处的“缓存的编译程序”部分。
Google Dart通过“快照”明确解决这个问题毫无价值——目标是通过加载预解析的代码版本来加快初始化和加载时间。
InfoQ 有一篇很好的文章 @ http://www.infoq.com/articles/google-dart
我认为正确的答案是“不总是”。据我了解,浏览器和服务器都在确定缓存内容方面发挥作用。如果您确实需要每次都重新加载文件,那么我认为您应该能够从 Apache 中配置它(例如)。当然,我认为用户的浏览器可以配置为忽略该设置,但这可能不太可能。
所以我想在大多数实际情况下,javascript文件本身是被缓存的,但是每次页面加载时都会动态地重新解释。
浏览器肯定会使用缓存,但是是的,每次页面刷新时浏览器都会解析 JavaScript。因为每当浏览器加载页面时,它都会创建 2 棵树 1.Content 树和 2.render 树。
此渲染树包含有关 dom 元素的视觉布局的信息。因此,每当页面加载时,都会解析 javascript,并且 javascript 的任何动态更改都会像定位 dom 元素、显示/隐藏元素、添加/删除元素将导致浏览器重新创建渲染树。但现代浏览器如FF和chrome处理方式略有不同,它们有增量渲染的概念,所以每当上面提到的js发生动态变化时,只会导致那些元素重新渲染和重绘。