在底部渲染阻塞延迟与移动脚本
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 移动到底部仍然显示渲染阻塞是一个主要问题。我的问题是我的理解是错误的还是我需要做些什么来解决渲染阻塞。 您是否尝试在window
的load
事件中加载脚本?
两者。最初它在 HEAD 中,但根据建议,我将它移到底部(就在 body 标签结束之前)。仍然显示相同的结果
通过在window
的load
事件中加载脚本,意味着在html
中不包含<script>
标签;而是在 window
load
事件处理程序中动态加载脚本,方法是在呈现 html
后动态创建 <script>
元素并将其附加到 document
。
【参考方案1】:
是的,即使在底部加载的脚本也必须具有 defere 属性,如果在您的网站设计和要求中可能的话
不,那些工具会寻找解析完成
取决于你要支持的IE版本,他们会有不同的建议
现在简单解释一下script
、defer
和async
,帮助大家理解原因:
脚本
简单的<script>
标签将在该点停止解析,直到脚本下载并执行。
异步
如果您将使用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
调用中添加 async
或 defer
属性。
【讨论】:
【参考方案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
【讨论】:
以上是关于在底部渲染阻塞延迟与移动脚本的主要内容,如果未能解决你的问题,请参考以下文章