每次页面刷新时,浏览器(IE和Firefox)都会解析链接的javascript文件吗?
他们可以缓存文件,因此我猜他们不会每次都尝试下载它们,但由于每个页面基本上是分开的,我希望它们可以拆除任何旧代码并重新解析它。
这是低效的,虽然完全可以理解,但我想知道现代浏览器是否足够聪明以避免网站内的解析步骤。我正在考虑网站使用JavaScript库的情况,如ExtJS或jQuery等。
答案 0 :(得分:330)
这些是我能够挖掘的细节。首先值得注意的是,尽管JavaScript通常被认为是在VM上进行解释和运行,但现代解释器的情况并非如此,它们倾向于将源代码直接编译为机器代码(使用IE的例外情况。
Chrome:V8引擎
V8有一个编译缓存。这使用源的哈希存储编译的JavaScript,最多可存储5个垃圾收集。这意味着两个相同的源代码将共享内存中的缓存条目,无论它们是如何包含的。重新加载页面时不会清除此缓存。
更新 - 2015年3月19日
Chrome小组已发布details about their new techniques for JavaScript streaming and caching。
脚本流优化了JavaScript文件的解析。 [...]
从版本41开始,Chrome会在下载开始后立即在单独的线程上解析异步和延迟脚本。这意味着解析可以在下载完成后的几毫秒内完成,并使页面加载速度提高10%。
通常情况下,V8引擎会在每次访问时编译页面的JavaScript,并将其转换为处理器可以理解的指令。一旦用户导航离开页面,该编译的代码就被丢弃,因为编译代码在编译时高度依赖于机器的状态和上下文。
Chrome 42引入了一种存储已编译代码的本地副本的高级技术,因此当用户返回页面时,可以跳过下载,解析和编译步骤。在所有页面加载中,这使Chrome可以避免大约40%的编译时间,并在移动设备上节省宝贵的电池。
Opera:Carakan Engine
实际上,这意味着每当脚本程序即将发布时 编译,其源代码与其他程序的源代码相同 最近编译,我们重用以前的输出 编译器并完全跳过编译步骤。这个缓存是相当的 在典型的浏览场景中有效,其中之后加载页面 来自同一网站的页面,例如来自新闻的不同新闻文章 服务,因为每个页面经常加载相同,有时非常大, 脚本库。
因此,JavaScript在页面重新加载时被缓存,对同一脚本的两个请求不会导致重新编译。
Firefox:SpiderMonkey引擎
SpiderMonkey使用Nanojit
作为其本机后端,一个JIT编译器。可以看到编译机器代码的过程here。简而言之,出现以在加载脚本时重新编译脚本。但是,如果在Nanojit
的内部we take a closer look,我们看到用于跟踪编译的更高级别监视器jstracer
可以在编译期间转换到三个阶段,从而为{{{{1}提供好处1}}:
跟踪监视器的初始状态正在监视。这意味着 spidermonkey正在解释字节码。每次蜘蛛侠 解释一个向后跳转的字节码,监视器记录下来 跳转目标程序计数器(PC)值的次数 跃升至。此编号称为PC的命中计数。如果命中 特定PC的计数达到阈值,目标是 认为很热。
当显示器确定目标PC很热时,它会查找哈希表 片段,看是否有一个片段持有本机代码 目标PC。如果它找到这样的片段,它会转换为 执行模式。否则它会转换到录制模式。
这意味着对于Nanojit
代码片段,本地代码将被缓存。意义不需要重新编译。
在页面刷新之间保留这些散列的原生部分并不清楚。但我会认为他们是。 如果有人能为此找到支持证据那么优秀。
修改强>: 有人指出,Mozilla开发人员Boris Zbarsky表示Gecko不会缓存已编译的脚本尚未。取自this SO answer。
Safari:JavaScriptCore / SquirelFish Engine
我认为此实施的最佳答案已经been given by someone else。
我们目前不会缓存字节码(或本机代码)。这是一个 我们已经考虑过的选项,但是,目前,代码生成是一个 JS执行时间的微不足道的部分(< 2%),所以我们不追求 现在这个。
这是由Safari的首席开发人员Maciej Stachowiak撰写的。所以我认为我们可以认为这是真的。
我无法找到任何其他信息,但您可以阅读有关最新hot
引擎here的速度改进的更多信息,或浏览源代码here,如果您有'感觉喜欢冒险。
IE:Chakra Engine
此字段中没有关于IE9的JavaScript引擎(Chakra)的最新信息。 如果有人知道,请发表评论。
这非常非官方,但对于IE的旧引擎实现,Eric Lippert(a MS developer of JScript)在博客回复here中指出:
JScript Classic就像编译语言一样,在任何JScript Classic程序运行之前,我们完全语法检查代码,生成完整的解析树,并生成字节码。然后我们通过字节码解释器运行字节码。从这个意义上说,JScript就像编译"作为Java。 不同之处在于JScript不允许您持久存储或检查我们的专有字节码。此外,字节码比JVM字节码高得多 - JScript Classic字节码语言只不过是解析树的线性化,而JVM字节码显然是为了在低级别的堆栈机器上运行。
这表明字节码不会以任何方式存在,因此字节码不会被缓存。
答案 1 :(得分:12)
Firefox(SpiderMonkey引擎)不缓存字节码。 (source)
WebKit(Safari,Konqueror)不缓存字节码。 (source)
我不确定IE [6/7/8]或V8(Chrome),我认为IE可能会进行某种缓存,而V8可能不会。 IE是封闭源,所以我不确定,但在V8中,缓存“编译”代码可能没有意义,因为它们直接编译为机器代码。
答案 2 :(得分:3)
据我所知,只有Opera缓存已解析的JavaScript。请参阅“缓存编译的程序”一节here。
答案 3 :(得分:2)
Google Dart通过“快照”明确解决这个问题是没有价值的 - 目标是通过加载预先准备好的代码版本来加快初始化和加载时间。
InfoQ有一个很好的写作@ http://www.infoq.com/articles/google-dart
答案 4 :(得分:0)
我认为正确的答案是“并不总是”。据我所知,浏览器和服务器都在确定缓存内容方面发挥作用。如果你真的需要每次都重新加载文件,那么我认为你应该能够在Apache中配置它(例如)。当然,我认为可以将用户的浏览器配置为忽略该设置,但这可能不太可能。
所以我想在大多数实际情况中,javascript文件本身都是缓存的,但每次页面加载时都会动态地重新解释。
答案 5 :(得分:0)
浏览器肯定会使用缓存,但是,浏览器会在每次页面刷新时解析JavaScript。 因为每当浏览器加载页面时,它都会创建2棵树 1.内容树和 2.nder tree。
此渲染树包含有关dom元素的可视布局的信息。因此,无论何时页面加载,javascript都会被解析,并且javascript的任何动态更改都会定位dom元素,显示/隐藏元素,添加/删除元素将导致浏览器重新创建渲染树。但像FF和chrome这样的现代broswers处理方式略有不同,它们具有增量渲染的概念,所以每当上面提到的js进行动态更改时,它只会导致这些元素再次渲染和重新绘制。