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

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

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

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

30399 次浏览

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

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

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

浏览器肯定会使用缓存,但是的,浏览器在每次页面刷新时都会解析JavaScript。 因为每当浏览器加载一个页面时,它都会创建2棵树 1.内容树和 2.渲染树。< / p >

这个呈现树由dom元素的可视化布局信息组成。因此,每当页面加载时,javascript都会被解析,javascript的任何动态变化都将导致浏览器重新创建渲染树,比如dom元素的定位,显示/隐藏元素,添加/删除元素。但是像FF和chrome这样的现代浏览器处理它略有不同,他们有增量渲染的概念,所以每当js有上面提到的动态变化时,它只会导致那些元素渲染和重新绘制。

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

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

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

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

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


Chrome: V8引擎

V8有一个编译缓存。它使用源的散列存储编译后的JavaScript,最多可进行5个垃圾收集。这意味着两个相同的源代码将共享内存中的缓存项,而不管它们是如何包含的。当重新加载页面时,此缓存不会被清除。

Source .


更新日期:2015年3月19日

Chrome团队发布了关于他们的JavaScript流媒体和缓存新技术的细节

  1. 脚本流

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

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

  1. 代码缓存

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

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


歌剧:卡拉坎引擎

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

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

Source .


Firefox: SpiderMonkey Engine

SpiderMonkey使用Nanojit作为本机后端,这是一个JIT编译器。编译机器代码的过程可以在在这里中看到。简而言之,它出现在加载脚本时重新编译脚本。然而,如果在Nanojit内部的我们来仔细看看,我们可以看到用于跟踪编译的高级监视器jstracer可以在编译期间转换为三个阶段,这为Nanojit提供了一个好处:

跟踪监视器的初始状态为监视。这意味着 Spidermonkey正在解释字节码。每次蜘蛛猴 解释向后跳转字节码,监视器记录 跳转目标程序计数器(PC)值的次数 跃升至。这个数字被称为PC的命中计数。如果命中 特定PC的计数达到阈值,则目标为 考虑热。< / p > 当监视器决定一个目标PC是热的,它在一个哈希表中 的片段,以查看是否有一个片段持有本机代码 目标PC。如果它找到这样一个片段,它就转换到 执行模式。

这意味着对于hot片段的代码,本机代码被缓存。这意味着不需要重新编译。 不清楚这些散列的本机部分是否在页面刷新之间保留。但我认为他们是。如果有人能找到支持这一点的证据,那就太好了。 < / p > < p > 编辑: 有人指出,Mozilla开发人员Boris Zbarsky已经声明,Gecko不缓存编译脚本然而,。取自这个SO答案.

.

Safari: JavaScriptCore/ squirrelfish引擎

我认为这个实现的最佳答案已经是别人给的

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

这是由Maciej Stachowiak编写的,Safari的主要开发人员。所以我认为我们可以相信这是真的。

我无法找到任何其他信息,但你可以阅读更多关于最新的SquirrelFish Extreme引擎在这里的速度改进,或者如果你有冒险精神,可以浏览源代码在这里


IE:查克拉引擎

在这个领域没有关于IE9的JavaScript引擎(Chakra)的当前信息。如果有人知道什么,请评论。

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

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

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

谷歌飞镖通过“快照”显式地解决这个问题是毫无价值的——目标是通过加载准备好的代码版本来加快初始化和加载时间。

InfoQ有一个不错的@ http://www.infoq.com/articles/google-dart