浏览器加载、解析和渲染页面是一个非常复杂的话题。这里我只对这个过程做一个非常笼统的概述,以便对这些过程有一个初步的了解。前端编程怎么样?优化页面,给予一些理论支持。为什么我们需要了解这些过程?了解浏览器资源加载可以让我们在引入外部样式和脚本资源时做出更合理的时机选择。了解浏览器文档解析可以让我们在构建DOM结构、组织CSS选择器等时选择更合理的写法了解浏览器结果的渲染,让我们设置元素属性,尽可能优化脚本操作,减少和避免不必要的redrawing和reflow以上三个过程并不是完全独立的,而是会重叠,并且会出现sideloading分析时渲染的工作现象。从用户输入的URL加载,再到获取网页文件也包括以下步骤:DNS解析,从缓存、本地Hosts、本地DNS服务器到根DNS服务器,直接返回任何级别的***结果,这一步获取目标服务器的IP端口解析,从URL中获取目标服务器的端口号。浏览器与Web服务器建立TCP连接(三次握手)。浏览器向服务器发送HTTP请求消息。服务器执行一些逻辑,例如数据库查询,最后生成并返回HTTP响应消息。经过以上步骤,浏览器获取到一个HTML文档,然后浏览器从上到下加载该文档,在加载过程中同时进行解析和渲染。在加载过程中,如果遇到外部CSS资源,浏览器会通过额外的资源线程发送请求获取CSS文件。同样,如果遇到图片资源,浏览器会再次发送请求获取图片资源。这些请求都是异步的,不影响HTML文件继续加载。但是,如果遇到JS资源,HTML文档的解析就会暂停,直到JS资源加载完成,解析完成后,才会恢复HTML文档的解析。浏览器的设计原因是JS很可能会修改DOM结构,这意味着JS脚本之后的一些资源加载和文档解析可能是不必要的工作。这里推导出一个常见的优化规则:在文档末尾结束'body'标签之前加载脚本文件,或者在脚本导入代码中添加defer或者async属性来表示它们可以被异步加载。另外,在HTTP1.X中,同一个域名下的并行资源请求数是非常有限的,不同浏览器的限制也不一定相同。针对这一点,衍生出多种优化方案:组合资源请求,比如使用Sprite组合多张图片为一张图片使用静态资源专用域名,扩大浏览器同时进行资源请求的数量。CSS资源的加载虽然不会影响JS资源的加载,但是会影响JS的执行:这是因为JS内部可能会执行一些依赖的CSS样式操作,比如获取元素大小,浏览器必须保证:在执行JS之前下载和解析CSS资源。所以如果有需要提前执行的JS脚本,可以将JS导入放在CSS导入之前。浏览器解析HTML文档主要包括以下几个部分:将HTML文档解析成DOMTree,DOMTree由DOM元素和属性节点组成。树的根是Document对象。将CSS解析成样式表对象,是CSS选择器和对象CSS规则的集合,JS脚本分析,可能会改变DOMTree和元素样式,最终体现DOMTree和CSS样式表对象的更新。渲染这个过程就是为浏览器构建渲染树的过程。渲染树是DOM树的可视化表示,是DOM编号和样式表对象的组合,所以DOM树中一些不可见的元素不会被插入到渲染树中,比如
或者display:none元素。一些脱离文档流的元素(绝对或浮动元素等)在两棵树上的位置并不完全相同,渲染树会识别真实位置,只将占位符放在原来的位置。在呈现期间,浏览器会为每个元素查找在样式表对象中定义的可变数量的样式规则。这里需要指出CSS选择器匹配的问题。多个选择器从右到左匹配。太深的选择器不利于风格搜索。创建渲染树后,进行布局。这个过程根据渲染对象的信息计算出每个渲染对象的位置和大小,并将其放置在浏览器窗口的正确位置。如果布局完成后修改了DOM,此时可能需要重新布局。每个渲染对象都有自己的布局方法。同样,渲染树的布局可以是全局的也可以是局部的。例如,改变窗口的大小或修改根元素的大小或字体大小都会带来全局的重新布局。如果仅仅改变某个内部渲染对象可能会带来局部重新布局。布局完成后,浏览器会遍历上一步得到的渲染树,不断调用渲染器的渲染方法,将对应渲染器的内容显示在屏幕上。下图表示WebKit浏览器的解析渲染过程。另外需要说明两个概念,Repaint和ReflowRepaint:改变不影响布局的属性,比如背景颜色Reflow:元素的几何尺寸发生了变化,需要重新验证和计算RenderTree.部分或全部渲染树已更改。这就是Reflow,或者说LayoutReflow的成本比Repaint的成本高很多。DOMTree中的每个节点都有回流的方法,一个节点的回流很可能会引起子节点的回流,甚至父节点和同级节点的回流。在一些高性能的电脑上可能没问题,但是如果reflow发生在手机上,那么这个过程就很痛苦,很耗电。因此,以下操作可能会比较昂贵。当你添加、删除或修改DOM节点时,移动DOM的位置或制作动画时,会导致Reflow或Repaint。当你修改CSS样式时。当你调整窗口大小时(移动端没有这个问题),或者滚动时。当您修改网页的默认字体时。display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。基本上,回流有以下原因:初始:当网页被初始化时。增量:当一些Javascript正在操作DOM树时。Resize:部分组件的大小发生了变化。样式更改:如果CSS的属性发生更改。Dirty:同一帧的子树上发生多次Incremental回流。浏览器针对频繁的重绘和重排做了一些优化。例如,浏览器会累积一批回流操作,然后进行一次回流。这也称为异步回流或增量异步回流。但在某些情况下,浏览器不会这样做,例如:调整窗口大小,更改页面的默认字体等。对于这些操作,浏览器会立即回流。页面渲染优化虽然浏览器已经尽力优化了页面渲染,但是在了解了浏览器的文档加载、渲染和解析过程之后,我们需要对自己编写的代码做一些相应的优化和优化。更好的做法:简化DOM层级简化CSS选择器结构发布少量首屏样式以减少内联脚本中不必要的DOM操作,尽量通过修改类名或动画元素来缓存DOM查找和DOM样式信息样式动画尝试使用绝对或固定定位元素,这些元素在屏幕外不可见或滚动时动画尝试停止