Web渲染性能,渲染顺序,看完这个你就全懂了(二)

Web渲染性能,渲染顺序,看完这个你就全懂了(二)

上一篇,我们介绍了DOM,CSSOM和渲染树是怎么回事,如果有不知道的,最好先回顾一下这篇文章Web渲染性能,DOM,CSSOM和渲染,看完这个你就全懂了(一), 接下来将继续我们的渲染历程。

渲染顺序

理解这个过程对开发设计人员来说很关键,它会帮助我们设计站点的时候充分考虑到用户体验和性能问题。页面加载后,浏览器会构造DOM,CSSOM和渲染树,当这些都创建好之后,就会开始在屏幕上绘制每一个元素

布局操作

首先浏览器给每个渲染树节点创建布局(layout)信息, 它包含了节点的将来显示的位置数据(像素点位置)。这个过程叫布局(Layout),也可以叫回流(reflow), 因为它也可能发生在窗口的大小改变,滚动等事件或DOM元素操作中。

注:我们应该尽量避免页面产生多次布局操作,因为这是代价昂贵的操作。

显示操作

到现在为止,我们已经有了一棵渲染树,也就是节点位置列表,包含了需要显示的所有信息。

因为渲染树上的节点可以重叠显示,它们的CSS属性,决定了它们的外观,位置,如何变化(动画)。我了更好的控制渲染,浏览器引入了层的概念。建立层,浏览器可以高效地在页面生命周期内执行显示操作。层也可以帮助元素以堆栈的形式显示(Z轴方向)。

在每一层,浏览器将会显示元素的每一个像素,比如边框,背景,颜色,阴影,文字等。这个过程也叫栅格化。为了改进性能,浏览器必须使用不同的线程去做这种栅格化操作。

这个层跟Photoshop中的层类似,你可以通过Chrome开发者工具看到页面中的不同层。打开开发者工具->更多工具->选择层,你将会看到更多细节。

注:栅格化通常是CPU完成的,但现在我们有新技术可以使用GPU来做这个操作,从而提高性能

合成操作

直到现在,我们还没有在显示器上画出任何一个像素。我们有的只是一些不同的层(位图Bitmap Image),这些层将会以特定的顺序被显示出来。在合成操作中,它们将被发送给GPU,最终显示在显示屏上。

一次性发送所有层显然是低效的。因为如果有回流或者重绘操作,这个每次都会发生。所以一个层会被打碎成很多个可显示的小块(Tiles)。你可以在开发者工具的渲染面板中看到这些小块。

综合上面的信息,我们可以看到浏览器的事件顺序,我们把这个执行顺序叫做关键渲染路径,如下图。

关键渲染路径(Critical Rendering Path)

浏览器引擎

创建DOM树,CSSOM树和处理渲染逻辑的工作,是被一个叫做浏览器引擎的软件完成的。它内置于浏览器中。这个引擎包含了渲染所需要的所有东西,能够把从HTML字符串文档最终转化成屏幕上的像素点。

如果你听人们讨论WebKit, 他们就是在说浏览器引擎。WebKit是APPLE Safari浏览器的默认引擎。Google Chrome使用的是Blink, 微软最新的Edge浏览器也使用了跟Chrome一样的引擎。还有一些其他公司的,比如Firefox…

浏览器中的渲染过程

我们都知道,JavaScript语言是遵循ECMAScript标准的, 因此每个JavaScript引擎比如V8,Chakra,Spider Monkey等,都被必须遵守这个标准。

有了这个标准,运行JavaScript就能给我们一致的体验,无论是在浏览器中,还是Node.js中,Deno等环境中运行相同的JS代码,都能给我们相同的结果。。这很棒,并且会提高我们的产品质量。

然而,这种情况在浏览器渲染中就不存在了,尽管HTML,CSS,JavaScript,这些语言的标准被一些机构控制,但浏览器把它们组合到一起,如何渲染出来,这个过程没有标准化。各个公司就各个公司的办法。比如Chrome就跟Safari的做法不一样。

因此很难预测在一个特殊浏览器中的渲染顺序和机制。尽管如此,HTML规范也做了些努力来标准化渲染操作。但是浏览器怎么遵守,遵守多少完全取决于他们自己。

除了这些不一致性,有些共通的东西是在所有浏览器中是一样的。 让我们来理解一下通常浏览器渲染事件的过程是怎么样的。

解析和外部资源

解析是读取HTML构造DOM树的过程。所以这个过程也叫DOM解析,做这个工作的程序叫DOM Parser。

大多数浏览器提供了DOMParser API来构造一个DOM树。你可以试着构造一个DOMParser的实例,然后使用parseFromString方法,看看可以构造出一个什么DOM树。

当浏览器请求一个页面,服务器返回了HTML文本(Content-Type设成text/html), 浏览器可以在只接收到整个文档中的开始几行或几个字符就开始解析操作。所以浏览器可以增量地构造DOM树,一次一个节点地从头到尾解析。

在上面这个例子中,我们访问incremental.html文件,设置网速只有10kbps,这样它会花很长时间来下载这个包含了1000个H1元素文件。从下图可以看到,浏览器从最初的收到的一些字节就开始构造DOM树,并把他们显示出来。剩下的东西还在后台下载中,就这样边下载边解析。

上面是该请求的性能图表, 你会看到这些事件发生的时间。当他们发生的越早,用时越短,说明用户体验越好。

FP表示首次渲染,表示浏览器开始在显示器上显示东西了。可能就是简单到显示Body中背景的第一个像素。

FCP表示首次内容渲染,说明浏览器已经渲染了图片或文字的第一个像素

LCP表示最大内容渲染,说明浏览器渲染了最大的一块文字或图片

L表示onload事件,是由浏览器的window对象发出的。类似的DCL由document对象发出,它冒泡至window,这样你就可以在window对象上监听它。这些事件有些复杂,我们接下来讨论它。

只要浏览器解析时碰到外部文件,它就会开始后台下载那个文件(非主线程)。比如JavaScript , CSS , image 或者其他任何外部资源都会这样。

最重要的就是要记住,解析通常发生在主线程。如果主线程解析JavaScript很忙,DOM解析操作就会停止工作,直到主线程再次空闲。之所以重要,因为只有script标签(JavaScript文件)会阻塞解析,而其他请求如image,stylesheet, pdf, video等外部文件不会阻塞解析。

解析阻塞脚本

当浏览器碰到script元素,如果是一段内嵌脚本,浏览器停止HTML解析,立即执行该脚本,然后继续解析HTML。所有内嵌JavaScript都会阻塞HTML解析。

如果script是外部脚本文件,浏览器会停止主线程工作(停止DOM解析),去下载js文件并等待其完成下载。当js下载后,浏览器会先执行下载的文件,然后继续主线程的DOM解析工作。如果浏览器发现另外一个script标签,它也会做同样的操作。为什么浏览器要停止当前的DOM解析工作呢?

我们知道,浏览器从JavaScript运行时暴露了DOM API,意味着我们可以用JavaScript访问或操作DOM元素。这就是那些动态的web框架可以工作的原理。比如React, Vue, Angular…但如果浏览器同时运行DOM解析和执行JS,那就会产生竞争关系,因为俩线程都可能改变DOM,最终导致DOM树不准确,所以DOM解析和JS执行都必须在主线程上。

尽管如此,当下载JS文件的时候,停止DOM解析在大多数情况下是完全没有必要的。所以HTML5增加了async属性给script标签。当浏览器碰到带async的script标签,它下载JS文件的时候不会停止DOM解析,一旦下载结束,就会阻塞DOM解析并且立即执行JavaScript代码。

我们还有一个更好用的defer属性,它跟async类似,下载的时候不会阻塞DOM解析。不一样的是,当defer文件下载完毕后,不会立即执行,会等到DOM树完全构造完成后才会执行。

在上面的例子中, parser-blocking.html文件,在30元素后,有一个阻塞解析的script, 这就是为什么浏览器开始显示了30个元素,然后停止了DOM解析,开始下载JavaScript文件。第二个script文件有defer属性,所以它会在DOM树完全建立后才执行。

如果看性能面板,浏览器一开始构造DOM树,有了一些HTML内容时,FP和FCP就发生了。我们就看到一下东西呈现出来了。

LCP发生于5秒后,因为需要处理JavaScript,所以DOM解析就会被阻塞5秒(JS文件的下载时间),并且只有30个文本元素被显示。但是这些东西还不足以成为最大的渲染内容(根据Google标准)。一旦JS文件下载并执行完成, DOM解析恢复,这时最大内容会被显示出来,所以LCP就触发了。

渲染阻塞-CSS

我们已经知道,任何其他外部资源,除了JavaScript文件,都不会阻塞DOM解析。所以CSS也不会直接阻塞DOM解析。。。等等。。。不会直接阻塞!!!什么意思?其实CSS会阻塞DOM解析,但我们需要先了解渲染过程。

浏览器引擎会将HTML文本变成DOM树,并且它也从stylesheet可以构造CSSOM树。但是DOM树和CSSOM树的构造都是在主线程上进行的,然后它俩合并成渲染树。我们已经知道DOM树是生成是增量的,一边读HTML一边生成节点添加到树上。但这不是CSSOM的构造过程,CSSOM树构造不是增量型的,是必须在某一特定时候发生的。

当浏览器发现块,它会解析所有的内嵌CSS并且更新CSSOM树,然后继续进行正常的DOM解析,inline样式也一样的处理。

然而,如果碰到外部CSS文件,事情就大不一样了。不像外部JavaScript文件,外部CSS文件不是解析阻塞资源,所以浏览器可以在后台继续下载,DOM解析仍然会继续。

另外,不像HTML,CSSOM构造不是增量型的,它不能边读边被构造。原因是一个文件末尾的CSS规则,可能会修改文件最顶部的规则。所以,如果进行增量构造,那就会导致渲染树的多次渲染,因此CSSOM节点随时可能会发生变化。那将会极大的降低用户体验,用户就可能看到页面效果不停的变化。所以当所有CSS规则被处理后,CSSOM树会被更新,然后渲染树也会被更新,最后才在显示器上呈现。

CSS确实是渲染阻塞资源。一旦浏览器发送一个请求去外部stylesheet,渲染树的构造就停止了。因此关键渲染路径(Critical Redering Path)也会被卡住,什么都显示不了。尽管如此,DOM树的解析仍然继续。

想一下浏览器可能已经使用老的CSSOM树就生成了渲染树,并且显示了一些东西在显示器上,然后又碰到了外部CSS文件,怎么办?这种情况很糟糕,一旦外部CSS文件下载完成,CSSOM树要被更新,渲染树也要被更新,所有那些已经被显示的元素要被新渲染树的内容所替代重新显示,这就会导致闪烁,是很糟糕的用户体验。

所以浏览器会等等stylesheet下载解析完成,这样CSSOM准备好,渲染树就可以准备好,渲染关键路径就不会被阻塞了。基于上述原因,通常建议所有外部CSS文件要尽早的被加载,最好是放在里。

另一种情况,外部JS文件已经被完全下载了,而外部CSS文件仍然在后台下载,这是浏览器会执行JS文件么?有什么危害么?

我们知道,CSSOM提供了JavaScript API来跟DOM元素的样式进行交互。比如,你可以读取更新元素的背景颜色el.style.backgourndColor 属性。这个与el关联的style属性暴露了CSSOM API。当stylesheet在后台下载的时候,JavaScript仍然会被执行,因为我们的主线程没有被阻塞。如果我们的JavaScript程序访问DOM元素的CSS属性,它会拿到当前CSSOM上的值。但是一旦stylesheet下载完成并被解析后,这就会导致CSSOM被更新,我们刚才JavaScript拿到的值就过时了,因此,在下载CSS的时候去执行JS是不安全的,应该尽量避免。

根据HTML5规范,浏览器可以下载一个JavaScript文件,但不会立即执行,直到所有stylesheets先被处理了。当一个stylesheet阻塞了JavaScript执行,这叫做脚本阻塞CSS。

上面这个例子,script-blocking.html包含了一个link标签(这个是CSS),然后跟着一个script标签(这个是JavaScript文件),这里JavaScript文件下载特别快,没有任何延迟,但CSS文件花费了6秒去下载。所以尽管JavaScript文件加载完成,它仍然不会被浏览器立即执行。只有当CSS文件被处理完,我们才能看到JavaScript输出的Hello World。

文档的DOMContentLoaded事件

这个事件DOMContentLoaded(简称DCL)在浏览器已经完成了所有DOM树的构建而发出的。这里有很多因素会影响这个事件的发生。

如果我们的HTML没有任何脚本,DOM解析不会被阻塞,DCL就会在解析完整个HTML立即发生。如果我们有阻塞的脚本,DCL就会等所有阻塞脚本被下载执行后再发生。

另外,如果我们把CSS考虑进来,事情就变得复杂了。尽管没有外部脚本,DCL仍然要等所有stylesheets被加载。因为DCL就记录一个时间点,说明整个DOM树准备好了,但如果CSSOM没有准备好,DOM树并不能被安全的访问。所以大多数浏览器会等CSSOM也准备好才发出这个事件。

DCL是最重要的网站性能指标之一,我们要优化它,越小越好。最佳实践之一就是使用defer,async标签给script元素。让这些脚本可以在后台下载。第二,我们要优化渲染阻塞的stylesheets.

Window的load事件

我们已经知道JavaScript可以阻塞DOM树的生成,带其他外部文件不行,比如CSS,图片,视频等等。

DOMContentLoaded事件记录了DOM树完成构造并且可以安全访问的时间点。window.onload记录了当外部的css和其他文件被下载完成的时间点。

在上面的例子中, rendering.html 文件有一个外部CSS文件在head中,它要花5秒被下载。因为它在head中,所以FP和FCP是在5秒后发生的。这个css文件会阻塞渲染,看不到任何东西。

在那之后,我们有个图片元素,大概需要10秒去下载,所以浏览器仍然继续在后台下载这个文件,并且继续进行DOM解析和渲染。

接下来,我们有3个JavaScript文件,他们将花3秒,6秒,9秒去下载。更重要的是,他们不是async的,这就意味着总共需要18秒顺序执行下载。而且直到前一个被下载并执行完成后,后面一个才会继续下载执行。尽管如此,我们的现代浏览器似乎采用了新的策略,更高效地下载了它们,所以总共用时9秒左右。因为最后一个文件下载会影响DCL, 所以DCL发生在9.1秒。

这时仍然有其他外部资源在下载,就是那张图片,它仍然在后台下载,大概花了10秒下载完成了,所以window.load事件在10.2秒被触发,意味着整个页面加载完成。

以上就是浏览器的整个渲染过程,希望可以帮助大家理解它的原理,也希望大家可以批评指正错误,一起讨论学习。

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
(0)
用户投稿
上一篇 2022年6月14日
下一篇 2022年6月14日

相关推荐

  • 揭秘缅甸的“夜”生活:是富人们的天堂,也是女孩们的“地狱”

    缅甸对于众多的小伙伴来说,可能有一点点了解,毕竟缅甸相对贫穷位于东南亚地区。 (此处已添加小程序,请到今日头条客户端查看) 其实也是我国的邻国,不仅仅拥有丰厚的历史,而且在年轻年代…

    2022年8月7日
  • 幻影车神3魔盗激情的精彩动图

    本文动图很多,流量党慎看。 2013年上映的《幻影车神3魔盗激情》,由阿米尔汗主演。 剧情并不复杂,简单点来说,就是一对双胞胎兄弟为父报仇和警察斗智斗勇的故事。 阿米尔·汗一人分饰…

    2022年8月10日
  • 轻薄游戏全都要?RTX3050游戏本看过来

    高考过后想必各位“准大学生”仍在纠结于大学第一台电脑的选购。笔记本是绝大多数童鞋的选择,受限于地域距离,宿舍限电等等制约因素,台式机并不符合大家对于移动场景使用的需求。而在笔记本领…

    2022年6月21日
  • 致自己的精湛句子,让人一见倾心

    一、百毒不侵的内心,往往会被一句简单的安慰打败,刀枪不入的伪装,常常在懂你的人面前彻底投降。 二、没有人可以和生活讨价还价,所以只要活着,就一定要努力。 三、真爱就像鬼,听说的人多…

    2022年6月25日
  • 名爵one的性价比高吗?

    当然,他的提速性能很不错的,而且各方面配置都很高,价格却很公道,车子的颜值很高,内饰方面看上去也满满的科技感。

    2022年7月25日
  • 励志文案“我还是会选择那种滚烫的人生 ”

    ·苦难从来就不是什么正能量的东西,千万不要感谢苦难, 你最应该感谢的,是走出苦难后浴火重生的自己。 ·没有不可治愈的伤痛,没有不能结束的沉沦,所有失去的,会以另一种方式归来。 ·希…

    2022年6月21日
  • 截至2022年8月份,适合学生党的4款手机,性能溢出价格低

    对于即将步入新校园生活的学生党们,最近应该都在考虑选择一款合适的手机吧?我总结了学生党选择手机的几个关键要素,第一是要有性价比,因为学生党毕竟还没有步入职场,没有过高甚至没有收入;…

    2022年8月15日
  • 为什么很多人宁可买顶配千元机,也不选入门旗舰机?原因只这3点

    如今很多人买手机越来越理性,手机厂商越来越卷,很多人在买手机的时候宁愿选择顶配千元机也不买入门旗舰,这是为什么呢,内行人告诉你,原因很真实。 第一、千元机配置也不错 现在千元机众多…

    2022年8月6日
  • 《沙石镇时光》单人模式主线更新将于8月30日推出

    国产游戏《沙石镇时光》官方宣布:单人模式主线更新将于8月30日推出!其中将包括家园扩建、新的怪物、游戏性能优化等新内容。此外官方还表示,多人模式内测已经开启,将争取在9月为所有玩家…

    2022年8月10日
  • 工信部再部署5G新基建 今年计划新增基站60万个 三大主线受关注

    《科创板日报》6月12日讯,人民日报12日报道,工信部将加快基础设施建设,今年计划新增5G基站60万个,还将实施5G行业应用“十百千”工程,选择10个垂直行业,每个行业形成100个…

    2022年6月13日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息