在底部渲染阻塞延迟与移动脚本

Posted

技术标签:

【中文标题】在底部渲染阻塞延迟与移动脚本【英文标题】:Render blocking defer vs moving script at bottom 【发布时间】:2017-04-26 00:37:53 【问题描述】:

我假设在底部移动脚本与使用 defer 或 async 属性相同。由于 defer 和 async 不完全兼容旧版浏览器,因此我在页面底部加载了脚本。

<html>
<body>
<!-- whole block of html -->
<script type='text/javascript' src='app.js'></script>
</body>
</html>

在此之前,我运行了 GTmetrix 和 Google PageSpeed insight 等性能基准测试工具。两者都将“渲染阻塞”参数显示为主要问题。我现在有点困惑,因为即使我将这些脚本移到底部以允许首先加载内容/html;这些工具仍然报告渲染阻塞是一个主要问题。

我确实查看了其他 *** 帖子,强调虽然在 底部加载的脚本必须具有 'defer' 属性。

我有几个问题:

    以上是真的吗? 这些工具是否专门寻找“延迟”或“异步”属性? 如果我必须提供一个回退 w.r.t defer(专门针对 IE 浏览器),我是否需要使用条件语句为 IE 加载非延迟脚本?

请提出最佳方法。提前谢谢你。

【问题讨论】:

不确定是什么问题?你想达到什么目的? 抱歉,如果我不能更好地描述它。我正在尝试优化一个 HTML 页面,该页面包含许多 javascript,主要是外部和应用程序库。 ** 由于许多性能工具表明 Javascript 会导致渲染阻塞,因此需要在 HTML 内容之后加载延迟加载。在我的情况下,将 javascripts 移动到底部仍然显示渲染阻塞是一个主要问题。我的问题是我的理解是错误的还是我需要做些什么来解决渲染阻塞。 您是否尝试在windowload 事件中加载脚本? 两者。最初它在 HEAD 中,但根据建议,我将它移到底部(就在 body 标签结束之前)。仍然显示相同的结果 通过在windowload事件中加载脚本,意味着在html中不包含&lt;script&gt;标签;而是在 window load 事件处理程序中动态加载脚本,方法是在呈现 html 后动态创建 &lt;script&gt; 元素并将其附加到 document 【参考方案1】:

    是的,即使在底部加载的脚本也必须具有 defere 属性,如果在您的网站设计和要求中可能的话

    不,那些工具会寻找解析完成

    取决于你要支持的IE版本,他们会有不同的建议

现在简单解释一下scriptdeferasync,帮助大家理解原因:

脚本 简单的&lt;script&gt; 标签将在该点停止解析,直到脚本下载执行

异步 如果您将使用async,那么脚本将不会停止解析下载,因为它将继续与其余的 html 内容并行下载。但是,该脚本将停止执行的解析,只有这样html的解析才会继续或完成

推迟 如果您使用defer,脚本将不会停止解析 html 数据以下载或执行脚本。因此,这是避免任何时间增加网页加载时间的最佳方法。

请注意,defer 有利于减少 html 的解析时间,但在每个网页设计流程中并不总是最好或合适的,所以在使用时要小心。

【讨论】:

为什么最后提到的脚本必须要有defer属性?整个 html 已经被解析,无论是否延迟脚本的执行都将遵循它们被提及的顺序。 【参考方案2】:

而不是async,可能是这样的(感谢@guest271314 的想法)

<!DOCTYPE html>
<html>
<body>
<!-- whole block of  html -->

<!-- inline scripts can't have async -->
<script type='text/javascript'>
function addScript(url)
document.open();
document.write("<scrip" + "t src = \"" + url + "\"></scr" + "ipt>");//weird quotes to avoid confusing the HTML parser
document.close();

//add your app.js last to ensure all libraries are loaded
addScript("jquery.js");
addScript("lodash.js");
addScript("app.js");
</script>
</body>
</html>

这是你想要的吗?如果需要,您可以在 document.write 调用中添加 asyncdefer 属性。

【讨论】:

【参考方案3】:

根据 HTML Spec 1.1 html 页面中的脚本块将阻止页面的呈现,直到 url 中的 javascript 文件被下载并处理。

在页面末尾添加脚本:允许浏览器继续页面渲染,因此用户将能够尽快看到页面渲染。

[Preferred] 向脚本标签添加 defer :向浏览器保证脚本中不包含任何 document.write 或文档更改代码,因此允许它继续渲染。

之前的帖子可能对你有用

Is it necessary to put scripts at the bottom of a page when using the "defer" attribute?

【讨论】:

【参考方案4】:

为什么最后提到的脚本必须要有defer属性?

嗯,答案是,通过添加延迟到最后一个脚本,您实际上减少了在绘制页面之前需要加载的关键资源的数量,从而减少了关键的渲染路径。

是的,当你到达最后一个被解析的 DOM 时你是正确的,但浏览器还没有开始绘制 DOM,因此 domContentLoadedEvent 被阻止,直到它完成绘制和渲染活动。

通过添加 async/defer,我们告诉浏览器资源对于渲染并不重要,它可以在 dom 内容加载后加载和执行。 这将更早触发 domContentLoaded 事件,并且 domContentLoaded 事件越早触发,其他应用程序逻辑就可以越早开始执行。

参考下面的谷歌链接,它清楚地展示了这个概念。 https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp

【讨论】:

以上是关于在底部渲染阻塞延迟与移动脚本的主要内容,如果未能解决你的问题,请参考以下文章

原来 CSS 与 JS 是这样阻塞 DOM 解析和渲染的

原来 CSS 与 JS 是这样阻塞 DOM 解析和渲染的

Web性能优化与HTTP/2

介绍同步加载异步加载延迟加载

ggplot2:移动(重新定位)图例以免阻塞图形框

javascript performence