一个微信面试题引发的血案--[译]什么阻塞了DOM?
2017-02-26 14:15
393 查看
转载自:http://www.jianshu.com/p/a4a88f4612d9
译者注:昨天一篇工作仅一年的前端工程师面试几个大厂的文章 引起了很多人的关注。一方面大家觉得作者太厉害了,工作近一年,能力竟然这么强(大叔我表示惭愧),另一方面几个微信面试题引起很多讨论。其中我比较感兴趣的一个题目是关于JavaScript和CSS阻塞DOM的。老实话讲,我以前也没太关注过,与其哀叹自己研究的不够深入,不如我们去学习弥补一下吧。这篇文章是我今天读到的,感觉不错,翻译一下给大家共享。
原文地址:https://www.keycdn.com/blog/blocking-the-dom/
原文作者:BRIAN JACKSON
译者:接灰的电子产品
当我们谈到web性能或者优化页面级别的速度时,非常重要的一点是要理解HTML和一个页面是如何在浏览器中构造的,这样你才能找到由于渲染阻塞导致的页面加载延迟。在这篇文章中,我们会深入了解是 什么阻塞了DOM 以及你应该怎样避免这种情况。
DOM是Document Object Model(文档对象模型)的缩写。它是为HTML和XML定义的一个编程接口,提供了文档的结构化表示(节点树状结构),同时也规定了使用脚本编程语言(例如JavaScript)应该如何访问以及操作DOM。这样一个节点树状结构是由不同的元素、父节点、子节点、兄弟节点等构成,它们彼此都有层级化的关系。下图是一个HTML DOM的例子:
HTML DOM
简单的讲,当你使用一个类似Chrome开发者工具的东东时,你可以看到一个可视化的DOM。你的HTML并不是DOM,但Chrome开发者工具为你展现了一个经过HTML或JavaScript加工之后的DOM。所以你可以把DOM理解成解析后的HTML。
Chrome开发者工具中体现的DOM
当我们分析页面速度时,我们总要考虑什么阻塞了DOM导致我们的页面加载出现延迟。这些阻塞因素我们可以叫做 阻塞渲染的资源 ,例如 HTML、CSS(也包括web font)和 JavaScript。
要查看什么阻塞了DOM的最简单的方法之一就是使用
和Google的
(可以通过 Chrome Canary 获得)。
在Chrome中启动开发者工具
Windows:
Mac:
切换到
Win:
现在你会看到一个加载时间瀑布图。这里有两个值得我们关注的东东:第一个是
我们知道CSS和JavaScript都是阻塞渲染的资源,它们都会在蓝色的DOMContent之前加载。请注意,图像是不会阻塞渲染的 ,所以如果有图像落在蓝线之前或之上你可以放心的忽略掉,当然优化图像也是很重要的一项工作。在这个例子里面,我们可以看到
Chrome开发者工具的网络面板中的加载时间瀑布图
你同样可以通过
Google PageSpeed Insights
我们下面要学习的是如何 通过优化关键渲染路径来避免CSS和JavaScript阻塞DOM 。尽管HTML也算是一个阻塞渲染的资源(译者注:记住HTML不是DOM),但DOM是可以增量构建的(译者注:所以优化的是CSS和JavaScript,而不是HTML)。
注意,我们无需追求在
如果你追求一个完全没有阻塞的CSS,那么你的唯一选项就是:在HTML中内联嵌入你的CSS。你可以把需要初始渲染的CSS,一般来讲就是第一屏的样式,直接放在
有几个可以辅助你完成内联样式嵌入的自动化插件
Grunt: grunt-critical-css
critical
你当然也可以使用JavaScript来加载CSS,但是这样做会导致页面在加载结束时重绘,因此这个选项对于网站访问者来说不一定会很理想。
在Chrome开发者工具中可以看到,我们做完内联样式优化之后的版本中
内联优化后的版本
现在我们再去
内联优化后的测试
当然这很不错,但一切取决于你的站点实际情况。大多数站点并不想内联嵌入所有的CSS,因为CSS的内容多少直接且显著的影响了页面下载的大小。对于小型站点或者就是个
即使在我们自己的KeyCDN主页上,我们也有一个阻塞渲染的CSS。但是,我们做了其他一些事情来优化CSS的加载时间,下面是我们的建议:
正确的调用你的CSS文件 (译者注:原文如此,感觉应该是位置或时机?)
使用
减少CSS的数量(尽可能放到一个CSS文件中)
Minify CSS文件(删除多余的空格、字符、注释等)
尽可能的减少样式数量(译者注:和第三条不同,是减少样式数量,不是文件数量)
一些用于最小化(Minify)CSS的工具
Grunt: grunt-contrib-cssmin
Gulp:gulp-minify-css
有一些关于JavaScript的最佳实践需要牢记在心:
把脚本放在页面尾部
使用async或defer指令来避免阻塞渲染
Patrick Sexton写了一篇非常好的博文: 如何延迟加载JavaScript
除去上面两条,我们对于JavaScript的另外3条建议是:
减少JavaScript的数量(尽量整合成一个JS文件)
Minify(最小化)JavaScript
如果JavaScript很小的话,可以内联嵌入
用于最小化JavaScript的自动化任务插件
Grunt:grunt-contrib-uglify
Gulp:gulp-uglify
通过把我们的JavaScript移动到页面尾部,以及使用
JavaScript优化后在Chrome开发者工具中的表现
那么在
达成100分
Web Fonts(Web字体)也被视为一种阻塞渲染的资源,因为它们是通过CSS加载的。你有两个选择:阻塞渲染或者延迟重绘(这种情况你需要处理 FOUT)。举个例子,在Chrome(36以上版本),Opera(23以上版本)和Firefox中有一个 three-second
timeout,在超时后,fall-back字体会被使用。
同样的我们有几个关于加载字体和优化关键渲染路径的小建议:
使用Web Font加载器或者字体加载API
使用内联嵌入优化字体加载
使用例如localStorage等存储方法
关于更多深入的加载Web Fonts、如何避免渲染阻塞以及FOUT/FOIT等可以查看这篇博文:
analyzing web font performance
我们希望到这里你可以对阻塞DOM、DOM树是如何构建的,为何会被CSS和JavaScript阻塞等问题有了一些了解。请再次记住不要追求
好了,下面是广告时间。前端学习群,前200人免费入群。现在还不满,从速哦!入群加笑笑微信:iamaixiaoxiao。
译者注:昨天一篇工作仅一年的前端工程师面试几个大厂的文章 引起了很多人的关注。一方面大家觉得作者太厉害了,工作近一年,能力竟然这么强(大叔我表示惭愧),另一方面几个微信面试题引起很多讨论。其中我比较感兴趣的一个题目是关于JavaScript和CSS阻塞DOM的。老实话讲,我以前也没太关注过,与其哀叹自己研究的不够深入,不如我们去学习弥补一下吧。这篇文章是我今天读到的,感觉不错,翻译一下给大家共享。
原文地址:https://www.keycdn.com/blog/blocking-the-dom/
原文作者:BRIAN JACKSON
译者:接灰的电子产品
当我们谈到web性能或者优化页面级别的速度时,非常重要的一点是要理解HTML和一个页面是如何在浏览器中构造的,这样你才能找到由于渲染阻塞导致的页面加载延迟。在这篇文章中,我们会深入了解是 什么阻塞了DOM 以及你应该怎样避免这种情况。
什么是DOM?
DOM是Document Object Model(文档对象模型)的缩写。它是为HTML和XML定义的一个编程接口,提供了文档的结构化表示(节点树状结构),同时也规定了使用脚本编程语言(例如JavaScript)应该如何访问以及操作DOM。这样一个节点树状结构是由不同的元素、父节点、子节点、兄弟节点等构成,它们彼此都有层级化的关系。下图是一个HTML DOM的例子:HTML DOM
用人话描述DOM
简单的讲,当你使用一个类似Chrome开发者工具的东东时,你可以看到一个可视化的DOM。你的HTML并不是DOM,但Chrome开发者工具为你展现了一个经过HTML或JavaScript加工之后的DOM。所以你可以把DOM理解成解析后的HTML。Chrome开发者工具中体现的DOM
什么在阻塞DOM?
当我们分析页面速度时,我们总要考虑什么阻塞了DOM导致我们的页面加载出现延迟。这些阻塞因素我们可以叫做 阻塞渲染的资源 ,例如 HTML、CSS(也包括web font)和 JavaScript。要查看什么阻塞了DOM的最简单的方法之一就是使用
Chrome开发者工具(Chrome DevTools)
和Google的
PageSpeed Insight。在下面的例子中,我们使用了最新的Chrome开发者工具
(可以通过 Chrome Canary 获得)。
在Chrome中启动开发者工具
Windows:
F12或者
Ctrl + Shift + I
Mac:
Cmd + Opt + I
切换到
Network(网络)面板,刷新页面(
Win:
Ctrl + R, Mac:
Cmd + R)
现在你会看到一个加载时间瀑布图。这里有两个值得我们关注的东东:第一个是
DOMContentLoaded是384ms(译者注:原文如此,看图的话应该是281ms),第二个就是瀑布图中的在蓝线之前的绿色部分(译者注:原图有点问题,蓝线看起来是紫色的)
我们知道CSS和JavaScript都是阻塞渲染的资源,它们都会在蓝色的DOMContent之前加载。请注意,图像是不会阻塞渲染的 ,所以如果有图像落在蓝线之前或之上你可以放心的忽略掉,当然优化图像也是很重要的一项工作。在这个例子里面,我们可以看到
style.css和
jquery.min.js都是阻塞渲染的资源。
Chrome开发者工具的网络面板中的加载时间瀑布图
你同样可以通过
Google PageSpeed Insights(https://developers.google.com/speed/pagespeed/insights/) 工具来验证我们上面的结论。下图中显示这两个文件的确是阻塞渲染的。
Google PageSpeed Insights
我们下面要学习的是如何 通过优化关键渲染路径来避免CSS和JavaScript阻塞DOM 。尽管HTML也算是一个阻塞渲染的资源(译者注:记住HTML不是DOM),但DOM是可以增量构建的(译者注:所以优化的是CSS和JavaScript,而不是HTML)。
注意,我们无需追求在
Google PageSpeed Insights的
100/100。例如,如果你链接引用了Google的web字体,那么无论你做什么,这个外部的
fonts.googleapis.com样式都始终会是一个阻塞渲染的资源。重要的是当你在处理有着10+个阻塞渲染资源的一个大型站点时,要理解清楚什么导致了延迟,有什么样的策略可以使这些资源可以更有效率的加载。
CSS
非渲染阻塞的CSS
如果你追求一个完全没有阻塞的CSS,那么你的唯一选项就是:在HTML中内联嵌入你的CSS。你可以把需要初始渲染的CSS,一般来讲就是第一屏的样式,直接放在 HEAD里面的
<style></style>中,然后剩下的CSS放在
</body>之前。这样做可以完全避免CSS阻塞渲染。
有几个可以辅助你完成内联样式嵌入的自动化插件
Grunt: grunt-critical-css
critical
你当然也可以使用JavaScript来加载CSS,但是这样做会导致页面在加载结束时重绘,因此这个选项对于网站访问者来说不一定会很理想。
在Chrome开发者工具中可以看到,我们做完内联样式优化之后的版本中
DOMContentLoaded减少到了
278ms:
内联优化后的版本
现在我们再去
Google PageSpeed Insights测试,会发现CSS已不是阻塞渲染的资源了。
内联优化后的测试
当然这很不错,但一切取决于你的站点实际情况。大多数站点并不想内联嵌入所有的CSS,因为CSS的内容多少直接且显著的影响了页面下载的大小。对于小型站点或者就是个
Landing Page,这种情况下内联嵌入CSS可以是一个不错的选项,如果你真的想完全避免CSS阻塞渲染的话。
我们的CSS建议
即使在我们自己的KeyCDN主页上,我们也有一个阻塞渲染的CSS。但是,我们做了其他一些事情来优化CSS的加载时间,下面是我们的建议:正确的调用你的CSS文件 (译者注:原文如此,感觉应该是位置或时机?)
使用
media queries(媒体查询) 来标记某些CSS为非阻塞资源 (译者注: 比如
<link href="other.css" rel="stylesheet" media="(min-width: 40em)">这样可以在其他屏幕尺寸加载时就不用加载这个css了)
减少CSS的数量(尽可能放到一个CSS文件中)
Minify CSS文件(删除多余的空格、字符、注释等)
尽可能的减少样式数量(译者注:和第三条不同,是减少样式数量,不是文件数量)
一些用于最小化(Minify)CSS的工具
Grunt: grunt-contrib-cssmin
Gulp:gulp-minify-css
JavaScript
非渲染阻塞的JavaScript
有一些关于JavaScript的最佳实践需要牢记在心:把脚本放在页面尾部
</body>之前的位置
使用async或defer指令来避免阻塞渲染
异步加载JavaScript
async允许脚本在后台下载,因此是无阻塞的。但是当下载完成的时刻,渲染又会阻塞了,这是因为脚本执行了。当脚本执行完毕,渲染又恢复了。
<script async src="foobar.js"></script>
延迟加载JavaScript
defer指令做的事情和
async基本一样,区别点在于
defer是严格要求脚本的执行顺序必须和在HTML中标记的顺序一样。所以说,可能存在一种情况,当一些脚本已经下载完毕,这些脚本不会立即执行,它们会等待其他脚本下载完成,因为那些脚本在HTML中出现在它们之前。
Patrick Sexton写了一篇非常好的博文: 如何延迟加载JavaScript
除去上面两条,我们对于JavaScript的另外3条建议是:
减少JavaScript的数量(尽量整合成一个JS文件)
Minify(最小化)JavaScript
如果JavaScript很小的话,可以内联嵌入
用于最小化JavaScript的自动化任务插件
Grunt:grunt-contrib-uglify
Gulp:gulp-uglify
通过把我们的JavaScript移动到页面尾部,以及使用
async指令之后,我们把
DOMContentLoaded显著的减少到了
144ms。我们可以看到
jquery.min.js文件现在出现在了DOM的蓝线之后了。
JavaScript优化后在Chrome开发者工具中的表现
那么在
Google PageSpeed Insights中同样的,由于我们已经异步加载了JavaScript,所以这一项的扣分不存在了,我们达成了
100/100。
达成100分
Web Fonts
Web Fonts(Web字体)也被视为一种阻塞渲染的资源,因为它们是通过CSS加载的。你有两个选择:阻塞渲染或者延迟重绘(这种情况你需要处理 FOUT)。举个例子,在Chrome(36以上版本),Opera(23以上版本)和Firefox中有一个 three-secondtimeout,在超时后,fall-back字体会被使用。
同样的我们有几个关于加载字体和优化关键渲染路径的小建议:
使用Web Font加载器或者字体加载API
使用内联嵌入优化字体加载
使用例如localStorage等存储方法
关于更多深入的加载Web Fonts、如何避免渲染阻塞以及FOUT/FOIT等可以查看这篇博文:
analyzing web font performance
小总结
我们希望到这里你可以对阻塞DOM、DOM树是如何构建的,为何会被CSS和JavaScript阻塞等问题有了一些了解。请再次记住不要追求 Google PageSpeed Insights的
100/100,重要的是理解你的渲染阻塞资源是如何阻塞DOM的以及你会怎样正确的优化使得页面的加载变快。
好了,下面是广告时间。前端学习群,前200人免费入群。现在还不满,从速哦!入群加笑笑微信:iamaixiaoxiao。
相关文章推荐
- 一个面试题引发的血案
- 一个馒头引发的血案 --enjoy
- 一个PHP菜鸟与cms引发的血案
- 一个“Spring轮子”引发的“血案”(5)
- 一个“Spring轮子”引发的血案(1)
- 一个“Spring轮子”引发的“血案”(5)
- 一个馒头引发的血案...请看完无极后观看此片,保笑死人不偿命
- 一个“Spring轮子”引发的血案(1)
- 一个“Sprng轮子”引发的“血案”(3)
- 一个“Spring轮子”引发的“血案”(2)
- 一个“Sprng轮子”引发的“血案”(3)
- 一个馒头引发的血案的精彩评论
- 一个“Spring轮子”引发的“血案”(4)
- 一个“Sprng轮子”引发的“血案”(3)
- 一个“Spring轮子”引发的“血案”(4)
- 馒头版《吉祥三宝》-一个馒头引发的血案
- 一个“Spring轮子”引发的“血案”(2)
- 一个“Spring轮子”引发的“血案”(6)
- 一个“Spring轮子”引发的“血案”(6)
- 一个“Spring轮子”引发的“血案”(2)