浏览器页面渲染

当浏览器通过网络通信获取到HTML文件后(浏览器如何显示页面一),后根据响应体渲染页面;

1.解析内容和渲染流程

浏览器操作的内容

需要明确的是,浏览器获取到响应体文件后,其操作的对象分别是:

1.HTML/XHTML/SVG: 解析此三种文件生成DOM Tree
2.CSS::解析样式表,生成CSS规则树(CSS Rule Tree);
3.JavaScript:解析JS脚本,通过DOM API和CSSOM API 分别操作DOM Tree和CSS Rule Tree,达到浏览器与用户交互目的;
附:CSSOM(CSS 对象模型,https://www.w3cplus.com/javascript/cssom-css-typed-om.html)

浏览器渲染的流程

WebKit内核渲染流程

上图为WebKit内核页面渲染过程;

  • 1.首先浏览器将响应体解析成DOM TreeCSS Rule Tree
  • 2.解析过程中如果遇到<script>标签,会立即解析脚本,直到解析完
  • 3.根据DOM TreeCSS Rule Tree构建渲染树Render Tree
  • 4.页面的重绘(repaint)和回流(reflow);页面渲染完后,若JS操作了DOM节点,根据JS对DOM的操纵,进行重绘或者回流操作;

2.解析与构建

<!DOCTYPE html>
<html><head><meta name="viewport" content="width=device-width,initial-scale=1" /><link href="style.css" rel="stylesheet" /><title>Critical Path</title></head><body><p>Hello <span>web performance</span> students!</p><div><img src="awesome-photo.jpg" /></div></body>
</html>
// style.cssbody { font-size: 16px }p { font-weight: bold } span { color: red } p span { display: none } img { float: right }
浏览器解析
  • HTML解析

    如图,DOM Tree结构如上所示,与DOM Tree类似的是CSSOM树的生成,此过程中,需要将接收到的CSS规则(Style Rules)转换成CSSOM树,即:

  • CSS解析

  • JS脚本解析

    浏览器解析生成渲染树过程中,如果遇到<script>就会立即开始解析脚本,直到JS脚本运行完毕;再接着解析构建渲染树;如果脚本是外部的,会等待脚本下载完毕,再继续解析文档,JS解析会将改变DOM和CSS的地方分别解析出来,追加到DOM Tree和Style Rules上

  1. 为什么JS脚本应该放在</body>前面,即底部加载?
    因为页面渲染过程中,遇到JS脚本会阻塞整个页面的渲染,而立即执行JS程序脚本,直到执行完全,再接着渲染树的解析与构建;这种情况会造成渲染白屏;

  2. 为什么浏览器遇到JS脚本会停止渲染,而立即执行JS脚本?
    首先, JS是单线程机制,执行JS脚本和构建渲染树,不能并行处理,同一时间只能执行一个操作;
    其次,JS脚本会操作DOM API和CSSOM API对整个页面的渲染树进行重绘和回流操作,也就是浏览器在渲染过程中对最终将呈现的页面是未知的,阻塞渲染树的构建,是为了防止无效操作,节省资源;如果不阻塞DOM树的构建,若JS删除了A节点,那么浏览器构建A节点就是浪费资源;

  3. 防止JS阻塞渲染方法?
    将JS脚本放在body底部执行; script标签上增加属性 defer或者async
    defer和async区别:

从图中我们可以明确一下几点:
1.defer和async在网络加载过程是一致的,都是异步执行的;
2.两者的区别在于脚本加载完成之后何时执行,可以看出defer更符合大多数场景对应用脚本加载和执行的要求;
3.如果存在多个有defer属性的脚本,那么它们是按照加载顺序执行脚本的;而对于async,它的加载和执行是紧紧挨着的,无论声明顺序如何,只要加载完成就立刻执行,它对于应用脚本用处不大,因为它完全不考虑依赖。

构建渲染树

渲染树(Render Tree):由DOM树和CSSOM树结合生成;但并不是必须等DOM树及CSSOM树加载完成后才开始合并构建渲染树。三者的构建并无先后条件,亦非完全独立,而是会有交叉,并行构建。因此会形成一边加载,一边解析,一边渲染的工作现象。
构建渲染树,根据渲染树计算每个可见元素的布局,并输出到绘制流程,将像素渲染到屏幕上。

重绘(repaint)和回流(reflow)
  • 重绘(repaint): 不影响页面元素位置和大小,不影响渲染树的结构,比如元素颜色的修改,譬如某个div标签节点的背景颜色、字体颜色等等发生改变,但是该div标签节点的宽、高、内外边距并不发生变化,此时触发浏览器重绘(repaint);

  • 回流(reflow): 也有称回流,当渲染树节点发生改变,影响了节点的几何属性(如宽、高、内边距、外边距、或是float、position、display:none;等等),导致节点位置发生变化,此时触发浏览器重排(reflow),需要重新生成渲染树。譬如JS为某个p标签节点添加新的样式:“display:none;”。导致该p标签被隐藏起来,该p标签之后的所有节点位置都会发生改变。此时浏览器需要重新生成渲染树,重新布局,即重排(reflow)

注意:回流必将引起重绘,而重绘不一定会引起回流。

当页面布局和几何属性改变时就需要重排。下述情况会发生浏览器回流:
1、添加或者删除可见的DOM元素;
2、元素位置改变——display、float、position、overflow等等;
3、元素尺寸改变——边距、填充、边框、宽度和高度;
4、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
5、页面渲染初始化;
6、浏览器窗口尺寸改变——resize事件发生时;

  • 如何减少或者避免回流?

Reflow 的成本比 Repaint 的成本高得多的多。一个节点的 Reflow 很有可能导致子节点,甚至父节点以及兄弟节点的 Reflow 。在一些高性能的电脑上也许还没什么,但是如果 Reflow 发生在手机上,那么这个过程是延慢加载和耗电的。----浏览器的渲染原理简介

  1. 直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器);
  2. 让要操作的元素进行”离线处理”,处理完后一起更新;
    a) 使用DocumentFragment进行缓存操作,引发一次回流和重绘;
    b) 使用display:none技术,只引发两次回流和重绘;
    c) 使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
  3. 不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存;
  4. 让元素脱离动画流,减少回流的Render Tree的规模;

参考:
https://blog.csdn.net/qq_33505829/article/details/103419143
https://segmentfault.com/a/1190000010298038
https://blog.csdn.net/qq_32657025/article/details/79569213
https://www.cnblogs.com/chiangyibo/p/7052617.html
https://www.cnblogs.com/yuezk/archive/2013/01/11/2855698.html
https://coolshell.cn/articles/9666.html【重点】
https://www.w3cplus.com/javascript/cssom-css-typed-om.html【重点】

浏览器如何显示页面(二)相关推荐

  1. 浏览器如何显示页面(一)

    浏览器输入网址到获取响应的过程 1.输入网址:www.baidu.com,回车后... 2.查询DNS缓存,首先依次查询浏览器DNS缓存,操作系统本地缓存,路由器缓存以及ISP服务缓存,如果还查不到, ...

  2. 输入URL到浏览器显示页面的过程,搜集各方面资料总结一下

    面试中经常会被问到这个问题吧,唉,我最开始被问到的时候也就能大概说一些流程.被问得多了,自己就想去找找这个问题的全面回答,于是乎搜了很多资料和网上的文章,根据那些文章写一个总结. 写得不好,或者有意见 ...

  3. 从浏览器地址栏输入url到显示页面的步骤

    从浏览器地址栏输入url到显示页面的步骤(以HTTP为例) - 在浏览器地址栏输入URL - 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤     - 如果资源未缓存,发起新请求   ...

  4. python在浏览器运行一片空白_Webdriver启动Firefox浏览器后,页面显示空白

    在使用pycharm码代码时编译总是出错,后来验证发现浏览器启动后出现问题.白白耗了我2个小时.我把我的解决方案写出来,希望对大家有帮助. 1.现象:起初安装的时候总是能正常运行,有一天突然发现Web ...

  5. 从点击一个链接到浏览器显示页面,这个过程中发生了什么?

    这个过程可以分为六步 浏览器通过域名找出其IP地址(DNS解析) 浏览器和服务器建立连接(TCP/TP三次握手) 浏览器向服务器发送HTTP请求 服务器接受到请求并返回HTTP响应 浏览器解析渲染页面 ...

  6. 扫描二维码如何实现从微信内直接跳转外部浏览器打开指定页面

    很多朋友在分享转发APP下载链接或者其他H5网页的时候都会首选在微信内分享,因为对于用户来说,说到二维码大家第一反应就是打开微信扫一扫,这是用户习惯的问题,另外一个重要的原因就是微信具备很恐怖的裂变性 ...

  7. 从输入一个网址到浏览器显示页面经历的过程,如是等等

    过程 浏览器已经是我们上网必不可少的工具,更不可避免的是浏览各大网站,即输入网址–>浏览器显示页面.具体过程如下: 1. DNS域名解析系统对输入的网址进行解 DNS域名解析系统本质就是一个数据 ...

  8. html可以用搜狗浏览器打开网页,win8使用搜狗浏览器打开网页“显示WEB浏览器已对此页面进行了修改以帮助跨站脚本”怎么办...

    windows8系统自带IE浏览器,但是一些用户还是喜欢下载第三方浏览器,比如搜狗浏览器,使用搜狗浏览器过程中总会遇到一些故障问题,比如win8使用搜狗浏览器打开网页"显示WEB浏览器已对此 ...

  9. 微信扫二维码调用外部浏览器打开指定页面

    场景分析 很多朋友都已经习惯在微信内分享网页链接和二维码了,通过扫描二维码下载APP或打开网页也成为大家惯用且非常方便的方式了.如此微信就成为了扫描二维码重要的工具,说到二维码大家第一反应就是打开微信 ...

最新文章

  1. 实现一个通用的生产者消费者队列(c语言版本)
  2. 圆与平面的接触面积_视频:5.3RJ六年级上册圆的面积例题+习题讲解
  3. vb.net html标签,VB.Net - 获取元素html的字符串/值?
  4. c# task添加顺序_关于c#:Task和async等待所需的指导
  5. svn update中文报错_svn不能更新也不能提交!为什么?
  6. mysql修改默认的存储引擎
  7. 2018.12.27|区块链技术头条
  8. Android编译判定BoardConfig.mk的宏控是否打开或者有效的验证方法
  9. Python内置字符串函数的用法
  10. php 或取域名的ip,php如何获取域名IP地址代码函数
  11. intellij idea 导出可执行jar
  12. p6spy mysql8_P6Spy配置使用
  13. linux watchdog超时时间,S3C2440看门狗定时器(Watchdog)
  14. C++求球的面积与体积,公式一样输出结果不一样?
  15. 蓝桥杯Python初级组测试题之Turtle画图2
  16. windows10系统更新后,Windows.old 无法删除解决方法
  17. 电脑tcp协议设置成服务器,电脑tcp协议设置成服务器
  18. laradock、phpstrom、xdebug配置实现断点调试
  19. (一)数字图像处理简介
  20. JDBC--预编译的statement对数据库进行添加数据的操作

热门文章

  1. 2022年最新广西道路运输安全员真题题库及答案
  2. 一行代码解决vue数据量大卡顿问题
  3. 作为一名项目管理人,这几款软件帮了我很多
  4. ftp服务器上传文件不行,ftp服务器上传文件不行
  5. Android9 电池优化,Android 9 Pie正式发布!手势操作+优化电池,谷歌“亲儿子”尝...
  6. 虚拟云服务器的用途,云服务器的这几个用途你了解么?
  7. (转)PC+运动控制卡的控制方案
  8. R语言加载xlsx报错错误: JAVA_HOME cannot be determined from the Registry解决方法
  9. win7创建ftp服务器及FlashFxp的使用
  10. 如何把InputStream字节流和InputStreamReader字符流转换成我们能看懂的String字符串