浏览器渲染的本质
浏览器渲染是指浏览器将接收到的HTML、CSS和JavaScript等网页资源转换成用户可以在屏幕上看到的可视化内容的过程。这个过程包括解析文档、构建渲染树、布局计算以及最终的绘制四个主要阶段。
1. 解析文档
当浏览器接收到服务器返回的HTML文档后,它会开始解析这些文档。浏览器按照文档流的顺序逐行读取HTML代码,并构建出DOM(文档对象模型)。DOM是一个树状结构,代表了文档中的所有元素及其关系。
2. 构建渲染树
在DOM构建完成之后,浏览器会继续解析CSS样式表,并将它们应用到相应的DOM节点上。然后,浏览器会根据DOM树和CSSOM(CSS对象模型)构建渲染树。渲染树包含了所有需要显示的元素及其样式信息。
3. 布局计算
有了渲染树后,浏览器接下来会对树中的每一个节点进行布局计算,确定每个元素的位置、大小和其他几何属性。在这个阶段,浏览器会解决元素之间的相对位置关系,例如浮动、定位等。
4. 绘制
一旦布局计算完成,浏览器就可以将渲染树中的各个元素绘制到屏幕上。这个过程涉及到将元素的视觉属性(如颜色、字体、背景等)应用到屏幕上对应的像素点上。
5. 重排与重绘
如果网页内容发生变化(比如添加或删除DOM节点),浏览器需要重新进行布局计算,这就是所谓的“重排”。而如果只是样式变化而不影响布局,则只需要“重绘”。
理解浏览器渲染过程对于优化网站性能至关重要,因为合理的代码编写和资源加载策略能够减少不必要的重排和重绘,提高用户体验。
好了,这就是浏览器渲染的本质的大概介绍!!接下来就进入正题吧!!
形象了解浏览器渲染
我们试想一下当我们在浏览器上输入www.baidu.com 会发生什么呢?当我们按下回车键的时候又会发生什么呢?www.baidu.com 这是一段域名,其实说白了就是给IP地址套一层壳,通过域名可以解析为IP地址。说白了正是有域名这个概念才让我们访问网页更加方便。我们不用输入像192.168.1.1这种的一串数字。
当我们输入我们在浏览器上输入www.baidu.com 后电脑根本无法识别这个东西。电脑拿到这个域名后首先会进行DNS解析,可以帮我们把这该域名分析出来究竟是那个IP地址,网络通讯就是要确定双方的IP。然后解析出来的这个IP地址匹配百度的IP地址。第二步,通过IP协议确定双方的位置连的是哪里的网。第三步呢就是开始进行通讯。通讯之前先通过TCP协议进行建立连接,然后就开始数据传输。(走的是http协议)然后我就可以向百度服务器发送请求,请求就是一个个数据包(js写的ajax请求)。然后百度服务器再返回一个个数据包。然后进行TCP的四次挥手断开连接,此时就是一次计算机和百度服务器进行的一次通信,一个请求出去,一个响应回来了。这就是浏览器的请求过程大概!!
好了,那我们进入正题,谈谈拿回数据包后电脑该干什么事情。
首先呢浏览器会解析数据包得到html文件,css文件(将二进制的字节数据解析为字符串)
之后呢 浏览器将根据转化好的字符串进行词法分析转换做标记。流程如: 字节数据==》字符串==》(标记)Token==》Node节点(对象来描述)==》构建DOM树。最后将css文件转化为CSSOM树。浏览器会找到所有的span然后筛选出来哪些span是在a标签里边,然后又去找哪些a标签是被div包裹。
因此最好是不要用具体的标签选择器写css样式这样会消耗很多的性能,最好是取类名。
div>a>span{
color:red
}
接下来DOM+CSSOM==render树(渲染树只会包含显示的节点)
最后计算页面布局(回流),GPU绘制(重绘)
操作DOM慢的原因
当我们用js来操作DOM的时候就会有两个线程一个是页面的渲染线程,一个是js引擎线程。js这门编程语言可以操作html,如果同时工作两个线程可能会撞车,这就是一种不安全的渲染。因此是互斥的,因此js引擎线程的执行一定会阻塞html的加载,当我们通过js来操作DOM的时候就会涉及到两个线程的通信和切换,会造成性能上的损耗。我们可以把js写在html的下面。不仅仅是因为我们要获取到html里边的结构,写到上边获取不到。其次呢出于用户体验考虑,如果先执行js代码的话可能会消耗一段时间,那么用户打开页面后就会出现一段时间的空白,等js执行完后页面才开始渲染这样的效果很不好。
回流与重绘
回流:
1.页面初次渲染
2.增加、删除可见的DOM元素
3.改变元素的几何信息
4.窗口大小改变
5.字体大小的更改
重绘:
1.非几何信息被修改
它俩关系可以总结为回流包含于重绘,回流必定导致重绘,重绘不一定导致回流。回流开销性能是很大的。
let el=document.getElementById('app')
el.style.width=(el.offsetWidth+1)+'px'
el.style.width=1+'px'
这段代码出现了一次回流,如果没有渲染队列则是有两次。
浏览器的优化
浏览器会维护一个渲染队列,当改变元素的几何属性导致回流发生时候,回流行为
会被加入到渲染队列中,在达到阈值或者一定时间后(代码执行完毕)会一次性将渲染队列中所有的回流生效。
div.style.left='10px'
div.style.top='10px'
div.style.width='10px'
div.style.height='10px'
只回流一次
div.style.left='10px'
console.log(div.offsetLeft);
div.style.top='10px'
console.log(div.offsetTop);
div.style.width='10px'
console.log(div.offsetWidth);
div.style.height='10px'
console.log(div.offsetHeight);
读取这种几何信息后渲染队列强制刷新,回流四次。
offsetTop,offsetLeft,
offsetWidth,offsetHeight,
clientTop,clientLeft,
clientWidth,clientHeight,
scrollTop,scrollLeft,
scrollWidth,scrollHeight,
减少回流
1.让需要修改该几何属性的容器先脱离文档流不显示,
修改完后再回到文档流当中。这样可以大大提升性能
例如:
let ul=document.getElementById("demo");
ul.style.display="none";
for(let i=0;i<10000;i++){
let li=document.createElement("li");
let text=document.createTextNode(i);
li.appendChild(text)
ul.appendChild(li);
}
ul.style.display="block";
2.借助文档碎片
let ul=document.getElementById("demo");
let frg=document.createDocumentFragment()
for(let i=0;i<10000;i++){
let li=document.createElement("li");
let text=document.createTextNode(i);
li.appendChild(text)
frg.appendChild(li)
}
ul.appendChild(frg)
3.克隆元素
let ul=document.getElementById("demo");
let clone=ul.cloneNode(true)
for(let i=0;i<10000;i++){
let li=document.createElement("li");
let text=document.createTextNode(i);
li.appendChild(text)
clone.appendChild(li)
}
ul.parentNode.replaceChild(clone,ul);
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=21137,转载请注明出处。
评论0