Reflow、重绘及其优化渲染流程渲染引擎通过网络请求接收渲染内容,解析HTML抽象DOM树抽象Render树布局(layout)render树绘制render树抽象DOM树渲染第一步引擎的主要工作是解析HTML文档,并将解析后的元素转换为DOM树中实际的DOM节点。抽象CSSOM树浏览器在解析dom的时候,遇到一个link标签,引用了一个外部的css样式表。引擎会将css抽象成cssom来构建渲染树。HTML中的视觉指令与来自cssom树的样式数据相结合以创建渲染树。浏览器构建渲染树的过程大致是这样的:从DOM树的根开始,遍历每一个可见的节点。某些节点是不可见的(例如脚本标签、元标签等)并且被省略,因为它们没有反映在呈现的输出中。display:none也会导致节点被省略。对于每个可见节点,浏览器找到合适的匹配cssom规则并应用它们。它向可见节点发布内容和计算样式。每个渲染器代表一个矩形区域,通常对应一个节点的CSS框。它包括几何信息,如宽度、高度和位置,以呈现树的布局。创建渲染器并将其添加到树中时,它没有位置和大小。计算这些值称为布局。HTML使用基于流的布局模型,这意味着大多数时候它可以一次性计算出几何图形。坐标系是相对于根渲染器的。使用顶部和左侧坐标。布局是一个递归的过程,从根元素即html开始,每个renderer都会计算自己的位置和大小来绘制renderingtree,这个阶段会遍历renderertree,renderer的paint()方法被调用在屏幕上显示内容。渲染分为全局渲染和增量渲染处理脚本和样式表的顺序当解析器到达脚本标签时,会立即解析并执行脚本。文档的解析将暂停,直到脚本执行完毕。这意味着该过程是同步的,这就是为什么将脚本标记放在主体末尾之前的原因html5添加了一个选项来将脚本标记为异步的,以便它可以被其他线程解析和执行。回流和重绘(reflowandrepaint)回流:指元素的内容、结构、位置或大小发生了变化,需要重新计算样式和渲染树;重绘:表示元素的变化只影响节点的部分样式(背景颜色、边框颜色、文本颜色等),只需要应用新的样式来绘制这个元素;什么时候触发reflow和repaintrepaintredraw:reflow回流肯定会引起repaint重绘,redraw可以单独触发背景颜色,颜色,字体变化(注意:字体大小变化时会触发reflow)reflow回流:第一个页面渲染(初始化)DOM树变化(比如增加或删除节点)渲染树变化(比如padding变化)浏览器窗口调整大小当你查询布局信息时,包括offsetLeft,offsetTop,offsetWidth,offsetHeight,scrollTop/Left/Width/Height,clientTop/Left/Width/Height,并调用getComputedStyle()或IE的currentStyle,浏览器返回最新值,会触发回流。优化渲染性能,减少回流和重绘,减少回流和重绘,尽量避免改变布局属性。比如宽度,高度,左边,顶部。另外transforms或者opacity属性会引起重绘,做动画的时候要注意,尽量使用这两个属性;使用弹性盒子。避免多次读取部分布局属性(同上),将复杂的节点元素从文档流中分离出来,降低回流成本。Javascript避免使用setTimeoutsetInterval来更新视图,在微任务中render和修改dom后会提交修改需求。这样会在render之前提交修改请求,把script标签放在body结束之前,或者使用异步脚本(defer,async)把计算量大的js放到worker上执行,比如解析一个大的json文件CSS减少选择器的复杂性。避免一个一个修改节点样式,尽量一次性修改,减少样式修改影响的元素数量,使用cssText替换需要多次修改的样式属性//设置单个属性elt.style.color="蓝色";//在一条语句中设置多个样式elt.style.cssText="color:blue;border:1pxsolidblack";//在一条语句中设置多个样式elt.setAttribute("style","color:red;border:1pxsolidblue;");通过更改类名来修改样式DOM,将元素从文档流中取出对其进行多次修改将元素带回文档此过程将触发两次重排,第一次和第三次。将触发多次回流的步骤放在第二步。三种基本方法:display:none,然后修改样式,然后resume使用文档片段(documentfragment)在当前dom树外建一个子树,然后把它copy回document。varfragment=document.createDocumentFragment()...这里的dom操作可以减少回流和重绘的次数修改副本,完成后替换原元素varold=document.getElementById('#app')varclone=old.cloneNode(true)...这里的dom操作可以减少回流和重绘的次数old.parentNode。replaceChild(clone,old)缓存布局信息前面提到,在查询布局信息(offsetLeft...)时,也会造成reflow。我们在使用的时候可以缓存布局信息,减少回流次数。在此处粘贴<<高性能javascript中的示例>>:沿对角线移动myElement元素,一次一个像素,从位置100100开始,到位置500500结束。在超时循环的主体中,您可以使用以下//低效的myElement.style.left=1+myElement.offsetLeft+'px'myElement.style.top=1+myElement.offsetTop+'px'if(myElement.offsetTop>=500){stopAnimation();}//优化//在循环外层获取初始值varcurrent=myElement.offsetLeft...//直接使用当前变量,不再查询偏移量current++我的元素。style.left=current+'px'myElement.style.top=current+'px'if(current>=500){stopAnimation();}在元素动画时使元素动画脱离文档流,将导致底部元件的回流。这种影响可大可小,具体取决于元素在文档流中的位置。动画元素使用绝对定位使其脱离文档流。这里的旋转和跳跃不会影响它。整个页面的重排在动画结束时恢复定位,从而只将文档的其他元素向下移动一次。指DOM操作成本高的地方。参考高性能javascript。请参阅JavaScript的工作原理:渲染引擎??和优化其性能的技巧
