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