浏览器是否在每次页面加载时解析javascript?

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

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

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


答案 1

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


铬 : V8 引擎

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


更新 - 19/03/2015

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

  1. 脚本流式处理

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

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

  1. 代码缓存

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

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


歌剧 : 卡拉坎引擎

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

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


火狐 :蜘蛛猴引擎

SpiderMonkey使用JIT编译器作为其本机后端。编译机器码的过程可以在这里看到。简而言之,它似乎在加载脚本时重新编译脚本。但是,如果我们仔细查看内部,我们会发现用于跟踪编译的更高级别的监视器,可以在编译过程中转换三个阶段,从而为以下方面提供了好处:NanojitNanojitjstracerNanojit

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

当监视器确定目标 PC 处于热状态时,它会在片段哈希表中查看是否存在保存该目标 PC 的本机代码的片段。如果找到这样的片段,它将转换为执行模式。否则,它将转换为录制模式。

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

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


Safari : JavaScriptCore/SquirelFish Engine

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

我们目前不缓存字节码(或本机代码)。这是我们考虑过的一
个选项,但是,目前,代码生成是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字节码显然是为了在低级堆栈机器上运行。

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


答案 2

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

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

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

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