【问题标题】:Javascript non-blocking scripts, why don't simply put all scripts before </body> tag?Javascript 非阻塞脚本,为什么不简单地将所有脚本放在 </body> 标记之前?
【发布时间】:2011-10-13 06:49:50
【问题描述】:

为了避免javascript阻塞网页渲染,我们不能把所有要加载/执行的JS文件/代码都放在关闭&lt;/body&gt;标签之前吗?

所有的 JS 文件和代码只有在所有页面被渲染后才会被下载和执行,所以需要像这篇文章中关于 non blocking techniques to load JS files 的技巧那样的技巧。他基本上建议使用如下代码:

document.getElementsByTagName("head")[0].appendChild(script);

为了在让网页被渲染的同时延迟脚本加载,从而导致网页的渲染速度很快。

但是如果不使用这种类型的非阻塞技术(或其他类似的技术),我们不是通过简单地放置我们所有的 JS 文件(待加载/执行)在关闭&lt;/body&gt;标签之前?

我更惊讶,因为作者(在同一篇文章中)建议将他的代码放在结束 &lt;/body&gt; 标记之前(参见文章的“脚本放置”部分),所以他基本上是在加载脚本无论如何,在结束 &lt;/body&gt; 标记之前。那他的代码有什么用呢?

我很困惑,感谢任何帮助,谢谢!


更新

仅供参考,Google Analytics 正在使用类似的非阻塞技术来加载其跟踪代码:

<script type="text/javascript">
...
(function() 
{
   var ga = document.createElement('script');
   ga.type = 'text/javascript';
   ga.async = true;
   ga.src = 'your-script-name-here.js';
   var s = document.getElementsByTagName('script')[0];
   s.parentNode.insertBefore(ga, s); //why do they insert it before the 1st script instead of appending to body/head could be the hint for another question.
})();
</script>
</head>

【问题讨论】:

    标签: javascript nonblocking deferred-loading


    【解决方案1】:

    一般说不。即使在页面的所有内容之后加载脚本,加载和执行脚本也会阻塞页面。原因是您的脚本中可能存在写入命令。

    但是,如果您只想实现加载页面内容的速度,那么在&lt;/body&gt; 标签之前放置脚本标签的结果与动态创建脚本标签的结果相同。最显着的区别是,当您以常见的静态方式加载脚本时,它们会被一一执行,换句话说,不会并行执行脚本文件(在旧浏览器中,下载脚本也是如此)。

    【讨论】:

    • 感谢您的回答。几件事:1)你说:...possibility of presence of write commands in your scripts. 好吧,但是如果在页面呈现后执行脚本,则 document.write 命令不是一个选项,因为它会删除所有 HTML 页面内容。甚至通过非阻塞技术加载脚本也不允许我们使用 document.write 命令,因为在页面渲染后脚本仍然会被执行。
    • 2) 你确定使用非阻塞技术,脚本是并行加载的吗?我想知道如果scriptB使用scriptA,但scriptB在scriptA之前加载并执行会发生什么?!
    • @Marco — 因为你不能在非阻塞脚本中使用 document.write 脚本是非阻塞的!
    • @Quentin:这不是我说的吗?!我不明白。据我了解,如果我们想在页面渲染后加载和执行脚本,在任何情况下都不能使用document.write。因此,这不是选择使用文章中建议的非阻塞技术还是简单地将脚本放在
    【解决方案2】:

    异步加载(尤其是像分析 sn-p 之类的东西)的一个优点是,至少如果您将其放在顶部,它会尽快加载,而不会花费任何时间来呈现页面。因此,通过分析,在用户离开页面之前(可能在页面完全加载之前)实际跟踪用户的机会会更高。

    并且使用 insertBefore 而不是 append,因为如果我没记错的话有一个错误(我认为在某些 IE 版本中,另请参阅下面的链接,cmets 中有一些关于此的内容)。

    对我来说这个链接: Async JS 是迄今为止我发现的最有用的。特别是因为它也带来了问题,即使使用谷歌的分析代码,onload 事件仍然会被阻止(至少在某些浏览器中)。如果您不希望这种情况发生,最好将该函数附加到 onload 事件。

    为了将异步 sn-p 放在底部,实际上在您发布的链接中进行了说明。他似乎只是为了确保在不使用 onload 事件的情况下完全加载 DOM。因此,这可能取决于您的脚本正在做什么,如果您不操作 DOM,则没有理由将其添加到正文的底部。除此之外,我个人更愿意将它添加到 onload-event 中。

    【讨论】:

      【解决方案3】:

      如果您想要异步脚本。 如果 (HTML5) 异步标记在您所在的浏览器中可用,请使用它。这就是 Google Analytics 在您发布的代码中所做的事情(特别是 ga.async = trueMDN Link, scroll down for async 行)。

      但是,这可能会导致您的脚本在页面加载期间的任意时间加载 - 这可能是不可取的。在选择使用异步之前,有必要问自己以下问题。

      不需要用户输入?然后使用异步属性。

      需要响应按钮或导航?然后你需要将它们放在页面顶部(在头部),而不是使用异步标签。

      异步脚本以任意顺序运行,因此如果您的脚本依赖于(比如说)jQuery,并且 jQuery 被加载到另一个标签中,您的脚本可能会在 jQuery 脚本之前运行 - 导致错误。


      为什么人们把东西放在body标签的底部?如果脚本需要足够的时间来加载它会减慢/暂停网站,该脚本很可能会在网站加载后暂停/挂起网站(预计不同浏览器上的行为会有所不同) - 使您的网站显得无响应(单击按钮并且没有任何反应)。在大多数情况下,这并不理想,这就是发明异步属性的原因。


      或者,如果您的脚本需要很长时间才能加载 - 您可能希望(在测试之后)minifyconcatenate 您的脚本,然后再将其发送到服务器。

      我建议使用require.js 进行缩小和连接,它易于运行和使用。

      缩小会减少需要下载的数据量。

      连接脚本减少了到服务器的“往返”次数(对于一个 200 毫秒 ping 的远距离服务器,5 个请求需要 1 秒)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-13
        • 2012-06-30
        • 2015-08-19
        • 2017-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多