Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

解析页面渲染流程 #5

Open
Abiel1024 opened this issue Mar 28, 2018 · 0 comments
Open

解析页面渲染流程 #5

Abiel1024 opened this issue Mar 28, 2018 · 0 comments

Comments

@Abiel1024
Copy link
Owner

Abiel1024 commented Mar 28, 2018

学习前端很自然的就从html、css和js开始了。当你学习完基础的内容之后,如何才能写出优雅又高效的代码呢?这就得了解其原理了。

总的来说,页面渲染的过程:
DOM => CSSOM => Render Tree => Layout => Painting => composite

DOM与CSSOM

构建DOm与CSSOM的过程中,主要通过四个步骤。
字节流(Bytes) → 字符流(characters) → 词语(Tokens)→ 节点(nodes) → object model.

字节流是通过协议获取到的数据,通过解码转换为字符流,也就是日常编写的代码。

拿到字符流之后,浏览器会根据字符流去解释成Tokens,这里在渲染dom时会用HTMLTokenizer类和XSSAuditor。一个进行分析,一个进行验证(安全考虑)。构建CSSOM则会用CSSParser类来实现。

构建渲染树

当DOM树和CSSOM都有了后,就要开始构建渲染树了。
一般来说,渲染树和DOM树相对应的,但不是严格意义上的一一对应。
因为有一些不可见的DOM元素不会插入到渲染树中,如head这种不可见的标签或者display: none等。
整体的流程是这样的:
image
创建完RenderObject之后,浏览器就能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。

渲染

创建完RenderObject后,webkit会根据盒模型计算css样式,然后构建出一个渲染树,根据计算的渲染树进行布局,即让浏览器知道哪个节点在屏幕中是哪个位置,样式是什么样子的,这一步成为回流。最后浏览器,要按照计算的数据,将内容显示到屏幕上,这一步称作重绘。所以一个页面显示完成,至少要进行一次回流和重绘。当时当js修改了dom结构或样式,就可能导致了重新布局(Layout)或渲染。
所以回流必将引起重绘,而重绘不一定会引起回流。

回流

意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树。

什么会引起回流?

1.页面渲染初始化
2.DOM结构改变,比如删除了某个节点
3.render树变化,比如减少了padding
4.窗口resize
5.最复杂的一种:获取某些属性,引发回流,
很多浏览器会对回流做优化,会等到数量足够时做一次批处理回流,
但是除了render树的直接变化,当获取一些属性时,浏览器为了获得正确的值也会触发回流,这样使得 
浏览器优化无效,包括
    (1)offset(Top/Left/Width/Height)
    (2) scroll(Top/Left/Width/Height)
    (3) cilent(Top/Left/Width/Height)
    (4) width,height
    (5) 调用了getComputedStyle()或者IE的currentStyle

重绘

 元素发生的改变只是影响了元素的一些外观的时候,此时只需要应用新样式绘制这个元素就可以了。

什么会引起重绘?

背景色
边框颜色
文字颜色

回流的成本开销要高于重绘,而且一个节点的回流往往回导致子节点以及同级节点的回流, 所以优化方案中一般都包括,尽量避免回流。

针对回流优化方案。

减少逐项更改样式,最好一次性更改style,或者将样式定义为class并一次性更新
避免循环操作dom,创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添 加到window.document
避免多次读取offset等属性。无法避免则将它们缓存到变量
将复杂的元素绝对定位或固定定位,使得它脱离文档流,否则回流代价会很高

最后一点,又会涉及到另一个知识点。

简单层与复合层
渲染中的绘制,可以结合复合层和简单层的概念来讲。
首先,普通文档流内可以理解为一个复合图层(这里称为默认复合层,里面不管添加多少元素,其实都是在同一个复合图层中)
其次,absolute布局(fixed也一样),虽然可以脱离普通文档流,但它仍然属于默认复合层。
然后,可以通过硬件加速的方式,声明一个新的复合图层,它会单独分配资源
(当然也会脱离普通文档流,这样一来,不管这个复合图层中怎么变化,也不会影响默认复合层里的回流重绘)
可以简单理解下:GPU中,各个复合图层是单独绘制的,所以互不影响,这也是为什么某些场景硬件加速效果一级棒
可以Chrome源码调试 -> More Tools -> Rendering -> Layer borders中看到,黄色的就是复合图层信息

将该元素变成一个复合图层,就是传说中的硬件加速技术
具体可以参考http://web.jobbole.com/83575/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant