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

时间:2009-07-08 08:49:55

标签: javascript browser-cache javascript-engine

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

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

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

6 个答案:

答案 0 :(得分:330)

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


Chrome:V8引擎

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

Source


更新 - 2015年3月19日

Chrome小组已发布details about their new techniques for JavaScript streaming and caching

  1. 脚本流
  2.   

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

         

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

    1. 代码缓存
    2.   

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

           

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


      Opera:Carakan Engine

        

      实际上,这意味着每当脚本程序即将发布时   编译,其源代码与其他程序的源代码相同   最近编译,我们重用以前的输出   编译器并完全跳过编译步骤。这个缓存是相当的   在典型的浏览场景中有效,其中之后加载页面   来自同一网站的页面,例如来自新闻的不同新闻文章   服务,因为每个页面经常加载相同,有时非常大,   脚本库。

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

      Source


      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)

正如其他答案所述,Opera会这样做。 (source

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进行动态更改时,它只会导致这些元素再次渲染和重新绘制。