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


190

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

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

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


4
我的2c:我认为缓存已解析的Javascript文件的性能优势太小,无法进行有意义的优化。
伊泰·马曼

2
根据我的基准,这实际上可能很重要。例如,jQuery的加载时间约为30毫秒(在快速台式机上),其中20%仅将代码解析为可执行的表示形式,其余的则在执行它,即在这种情况下初始化jQuery对象。如果您在移动设备上,并且使用两个或三个库,则此延迟可能是相关的,因为JavaScript执行受阻,并且页面基本上是空白的,直到将每个JS脚本加载到内存中为止。
djjeck 2012年

Answers:


338

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


Chrome:V8引擎

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

资源


更新-19/03/2015

Chrome小组已经发布了有关JavaScript流和缓存新技术的详细信息

  1. 脚本流

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

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

  1. 代码缓存

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

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


歌剧:卡拉坎引擎

实际上,这意味着每当要编译的脚本程序的源代码与最近编译的某些其他程序的源代码相同时,我们就重复使用编译器的先前输出,并完全跳过编译步骤。此缓存在典型的浏览方案中非常有效,因为在这种情况下,一个页面从同一站点逐页加载,例如新闻服务中的不同新闻报道,因为每个页面通常都加载相同的脚本库,有时甚至很大。

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

资源


Firefox:SpiderMonkey引擎

SpiderMonkey使用NanojitJIT编译器作为其本机后端。可以在此处看到编译机器代码的过程。简而言之,似乎在脚本加载时会重新编译。但是,如果我们仔细研究一下内部结构,Nanojit就会发现jstracer用于跟踪编译的高级监视程序可以在编译过程中过渡到三个阶段,这对以下方面有好处Nanojit

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

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

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

编辑:它已经指出,Mozilla开发鲍里斯Zbarsky曾表示,壁虎不缓存编译脚本。从这个SO答案中获取


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字节码显然旨在在低级堆栈计算机上运行。

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


10
+1,出色的写作。但是,关于Firefox,请参阅此StackOverflow问题,其中Mozilla开发人员Boris Zbarsky解释说Gecko当前不这样做。
cha0site 2012年

谢谢,我在旅途中看到了这一点,但找不到其他支持证据。我将用它编辑答案。
Jivings

1
请注意,有关IE的说法是在2003年说的:IE9的JS引擎的第一个版本是2011
。– gsnedders

此外,Opera缓存JS字节码的范围不只是重新加载。(但是,不会缓存生成的机器代码)。
gsnedders'2

2
@Jivings将以上内容作为源。(我是
卡拉坎

12

如其他答案中所述,Opera做到了。(来源

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

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

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


1
IE6-8几乎肯定不会。IE9可以,但是我都没有任何证据。编译的JS可能不会被缓存在任何地方,因为它通常很大。
gsnedders

@gsnedders:我不确定IE8在技术上不能做到这一点,似乎它也可以编译为字节码(不是官方的,而是关闭的),因此没有技术原因不缓存它。IE9似乎添加了一个JIT来编译为本机代码。
cha0site 2012年

2
字节码已被IE永久使用。IE8中没有什么新内容。仅仅是给定一个解释器,解释器的性能比解析时间要慢得多,这完全不相关。IE9具有全新的(从头开始)JS引擎,因此两者之间没有任何关系。
gsnedders

3

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


谢谢,您还有其他浏览器系列的更多详细信息吗?
ajreal 2012年


0

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

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


0

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

该渲染树包含有关dom元素的视觉布局的信息。因此,每当加载页面时,都会对javascript进行解析,并且javascript进行的任何动态更改都将类似于定位dom元素,show / hide元素,add / remove元素,从而使浏览器重新创建渲染树。但是像FF和chrome这样的现代浏览器在处理它方面略有不同,它们具有增量渲染的概念,因此,只要上述js进行了动态更改,它只会导致这些元素再次渲染和重新绘制。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.