渲染过程的外部工作
这是咱们理解浏览器如何工作4篇博客的第3篇。之前,咱们介绍了 多过程架构 和 导航流程。在本文中,咱们将钻研渲染过程外部产生了什么。
渲染器过程波及web优化的许多方面。因为渲染过程外部产生了很多事件,因而本文只是概述。如果你想更加深刻,“web基础知识的性能优化局部”有更多的资源。
渲染过程解决web内容
渲染过程负责解决tab选项卡内产生的所有事件。在一个渲染过程中,主过程解决你发送给用户的大多数代码。如果有时候你应用web worker 或者 service worker,你的局部 javascript 由woker线程解决。排版和光栅线程也在渲染过程外部运行,以便高效,晦涩的渲染页面。
渲染过程的外围工作是将html、css和javascript转换为能够与用户交互的web页面。
解析
DOM结构
当渲染过程接管到导航提交的信息,并且开始接管html数据,主线程开始解析文本字符(html),并且将其转换为文档对象模型(DOM)。
DOM是一个浏览器对页面的外部示意,也是web开发者能够通过javascript与之交互的数据结构和API。
解析一个HTML文档到DOM是通过HTML规范来定义的。你可能留神到将HTML放到浏览器素来没有抛出过谬误。例如,短少闭合 </p> 是一个非法的HTML。谬误的标记例如 Hi! I'm Chrome! (b标签在i标签之前敞开),它被看成是 Hi! I'm Chrome!。这是因为HTML标准定义了如何优雅的解决这些谬误。如果你关怀这些事件是如何实现的,你能够浏览HTML标准中“错误处理和解析中奇怪的例子”一节。
子资源加载
一个网站通常会应用额定的资源,例如图片、css和javascript。这些文件须要从网络或者缓存中加载。主过程能够 在解析构建DOM的时候一个接一个的申请他们,但为了加快速度,“预加载扫描”会同时运行。如果在HTML外面有一些像img和link的内容,预加载会查看HTML解析生成的token,并且在浏览器过程中发送网络申请。
javascript会阻塞解析
当HTML解析发现一个script标签,它进行解析HTML文档,并且去加载,解析,并且执行javascript代码。为什么?因为javascript能够扭转文档的形态,应用document.write()能够扭转整个的DOM构造(解析模型概述在HTML定义里有一个好的绘图)。这是HTML解析为什么在复原HTML文档解析之前期待javascript执行。如果你像深刻理解javascript执行产生了什么,V8团队对于此的探讨在这。
提醒浏览器如何加载资源
web开发者有很多种形式能够发送提醒给浏览器按序加载资源。如果你的javascript没有应用document.write(),你能够增加 async 和 defer 属性给 <script> 标签。浏览器能够异步地加载和执行 javascript 代码,并且不会阻塞html解析。如果适宜的话你可能也会应用 javascript module。<link rel="preload">是一种告诉浏览器在以后导航须要尽可能早的下载资源的形式。你能够浏览更多的内容在这里 Resource Prioritization – Getting the Browser to Help You.
款式计算
只有一个DOM是不足以晓得页面长什么样子的,因为咱们能够在css中设置页面款式。主线程解析CSS并且为每个DOM节点精确地计算出款式。这是基于CSS选择器为每个元素利用对应款式的信息。你能够在 DevTools 中的 computed 局部看到这些信息。
即便你没有提供任何的CSS,每个DOM节点也会又一个computed款式。<h1>标签比<h2>标签展现进去大,并且为每个元素都定义了外间距。这是因为浏览器有一个默认样式表。如果你想晓得chrome有哪些默认的css,请查看这个chrome默认css。
布局
当初渲染过程晓得文档的构造和每个节点的款式,然而这些还不足以渲染一个页面。设想一下你在电话外面为你的敌人形容一副画。“这里有一个大红色的圆和一个小的蓝色正方形”这些信息不可能让你的敌人精确的晓得画到底是什么样子。
布局是一个寻找元素坐标的过程。主线程遍历DOM和计算款式,创立蕴含x,y坐标和边界框大小的布局树。布局树和DOM树有着类似的构造,然而它仅仅蕴含页面上可见元素的关联信息。如果利用了 display:none,那么这个元素就不是布局树的一部分(然而,一个visibility:hidden的元素在布局树中)。相似地,一个蕴含内容的伪类就像p::before{content: "Hi!"}被利用,它会蕴含在布局树中,即便它不在DOM中。
确定页面布局是一个有挑战的工作。即便最简略的页面,从上到下块布局,也必须去思考字体多大,哪里须要换行,因为这些都会影响段落的大小和形态;而且也会影响下一行的段落的内容。
CSS能够使元素浮动到一边,屏蔽溢出项,扭转书写的方向。你能够设想,这个布局阶段有一个艰巨的工作。在Chrome中,一个工程师团队都在为布局工作。如果你想理解更多他们的工作细节,请点击 演讲视频 观看乏味的记录。
绘制
有了DOM,款式,布局还是不足以渲染一个页面。假如你想模拟一幅画。你晓得大小,形态,元素的地位,然而你依然须要判断绘制的程序。
例如,会为一些元素设置z-index,在上面的例子中,依照HTML的程序绘制将会呈现谬误的渲染后果。
图8:页面元素依照HTML标记的程序呈现,因为未思考 z-index导致生成谬误的渲染图
在以后绘制步骤,主线程遍历布局树去生成绘制记录。绘制记录是对绘制过程的记录,例如“先背景,后文字,最初矩形”。如果你应用 javascript 在<canvas>元素上绘制,这个过程对你就比拟相熟。
图9:主线程遍历布局树并且生成绘制记录
更新渲染流十分低廉
在渲染流中要把握的最重要的一点是,在每一步中,应用上一步操作的后果去生成新数据。例如,如果布局树中的某些产生扭转,须要为受影响的文档局部从新生成绘制程序。
如果为某些元素设置动画,浏览器必须在每个frame两头去运行这些操作。咱们大多数的显示器都是每秒钟刷新60次屏幕;当你在每一帧中在屏幕上挪动物体时,动画对于人眼的显示都是平滑的。然而,如果错过了它们之间的帧,则页面将显示为“凌乱”。
图11:时间轴上的动画帧
即便渲染操作域屏幕刷新保持一致,这些计算依然运行在主线程上,这也意味着当你的利用运行javascript时会阻塞。
图12:时间轴上动画帧,但一个帧被javascript阻止
你能够将Javascript操作分成小块,并应用requestAnimationFrame()安顿在每个帧上运行。对于这个话题想要理解更多,你能够看 js优化执行。你也能够让你js运行在web woker下来防止阻塞主线程。
图13:在带有动画帧的时间轴上运行javascript小块
合成
你如何去画一个页面?
当初浏览器晓得了文档的构造,每个元素的款式,在页面外面的坐标和绘制程序,如何绘制一个页面?将这些信息转化为屏幕上的像素叫作光栅化(rasterizing)。
解决此问题的一个童稚的办法就是在视口外部栅格化。如果用户滚动页面,则挪动栅格化框架,并通过栅格化更多内容去填充缺失的局部。这是Chrome第一次公布时解决栅格化的形式。然而,古代浏览器运行着更为简单的过程,叫作合成。
什么是合成?
合成是将一个页面的各个局部分成多个层,别离对其栅格化的技术,在一个叫作合成线程的独立线程中合称为一个页面。如果产生滚动,因为图层曾经被栅格化,所以就不得不合成一个新的帧。能够应用雷同的形式,通过挪动图层生成一个新的帧来实现动画。
你能够在开发者工具的“Layers panel”中查看你的网站如何被划分为多个图层。
划分为图层
为了找出哪些元素应该在哪些图层,主线程遍历布局树为了生成图层树(在开发者工具中这部分在performance面板中被叫作“更新图层树”)。如果页面的某些局部应该是独立的层(例如滑入式侧边栏)没有生成,你能够在css中应用 will-change 属性去提醒浏览器。
你可能试图为每个元素提供图层,然而与页面的每帧进行栅格化相比,过多数量的图层合成会使得操作速度变慢,因而掂量应用程序的渲染性能特地重要。想理解更多这个话题,能够查看 Stick to Compositor-Only Properties and Manage Layer Count。
栅格化和合成脱离主线程
一旦图层树生成,并且绘制程序确定,主线程会提交这些信息给合成线程。合成器线程会栅格化每个图层。一个图层能够和整个页面的长度一样大,因而合成器会讲他们划分为图块,并且将每个图块发送给栅格线程。栅格线程栅格化每个图块,并且将他们存储在GPU中。
合成器线程会优先解决不同的栅格线程,因而能够首先对视口栅格化。一个图层还具备不同分辨率的平铺,用于解决放大放大的操作。
一旦图块被栅格化,合成器线程将手机信息叫作“draw quads”生成一个“compositor frame”。
draw quads | 蕴含例如图块在内存中地位以及思考页面合成的状况下在页面中合成图块的信息。 |
---|---|
compositor frame | draw quads汇合去展现一个页面的框架 |
而后合成器框架通过IPC提交信息给浏览器过程。此时,能够从更改浏览器UI的UI线程或者另外一个用于扩大的渲染过程增加另一个合成器框架。这些合成框架都被发送到GPU用于显示到屏幕上。如果滚动事件产生,合成器过程创立另一个合成器框架发送给GPU。
合成的益处是不波及主线程就能够实现。合成器线程不须要等到款式计算和Js执行。这是为什么合成动画被认为是最佳的平滑优化的起因。如果布局和绘制须要从新计算,则必须波及主线程。
总结
在这篇文章中,咱们深刻理解了从解析到合成的渲染流。心愿你当初能够获取到更多的对于网站优化的常识。
在上面也是本系列最初一篇文章中,咱们将更加深刻理解合成器线程,并且晓得当用户输出例如mouse move和click的时候产生了什么。