Bevor die Diskussionsseite neu gezeichnet und neu gestaltet wird. Sie müssen ein gewisses Verständnis für den Seitenrenderingprozess haben, wie die Seite HTML in Kombination mit CSS usw. im Browser anzeigt. Das folgende Flussdiagramm zeigt den Verarbeitungsablauf des Browsers für die Seitenrendering. Verschiedene Browser können leicht unterschiedlich sein. Aber im Grunde sind sie ähnlich.
Der Browser analysiert den erhaltenen HTML-Code in einen DOM-Baum. Jedes Tag in HTML ist ein Knoten im DOM-Baum, und der Stammknoten ist unser häufig verwendeter Dokumentobjekt. Der DOM-Baum enthält alle HTML-Tags, einschließlich display:none versteckt, mit JS dynamisch hinzugefügte Elemente usw.
Der Browser analysiert alle Stile (benutzerdefiniertes CSS und Benutzeragenten) während des Analysevorgangs werden Stile entfernt, die vom Browser nicht erkannt werden. IE entfernt Stile, die mit -moz beginnen, während FF Stile entfernt, die mit _ beginnen.
3. DOM-Baum und Stilstruktur werden kombiniert, um einen Renderbaum zu erstellen, der jedoch sehr unterschiedlich ist hat einen eigenen Stil und der Renderbaum enthält keine versteckten Knoten (z. B. display:none-Knoten und Kopfknoten). Da diese Knoten nicht zum Rendern verwendet werden und sich nicht auf das Rendern auswirken, werden sie nicht in das Rendern einbezogen Baum. Beachten Sie, dass durch „visibility:hidden“ ausgeblendete Elemente weiterhin in den Renderbaum aufgenommen werden, da sich „visibility:hidden“ auf das Layout auswirkt und Platz einnimmt. Gemäß dem CSS2-Standard wird jeder Knoten im Renderbaum als Box (Box-Abmessungen) bezeichnet, und das Seitenelement wird als Box mit Auffüllung, Rändern, Rändern und Position verstanden.
Sobald der Renderbaum erstellt ist, kann der Browser die Seite basierend auf dem Renderbaum zeichnen.
Reflow und Neuzeichnen
Wenn ein Teil (oder der gesamte) des Renderbaums aufgrund der Größe des Element, Layout, Ausblenden usw. ändern sich und müssen neu erstellt werden. Dies wird als Reflow bezeichnet. Jede Seite muss mindestens einmal umgebrochen werden, wenn die Seite zum ersten Mal geladen wird. Während des Reflows macht der Browser den betroffenen Teil des Rendering-Baums ungültig und rekonstruiert diesen Teil des Rendering-Baums. Nach Abschluss des Reflows zeichnet der Browser den betroffenen Teil auf dem Bildschirm neu.
Wenn für einige Elemente im Renderbaum Attribute aktualisiert werden müssen, wirken sich diese Attribute nur auf das Erscheinungsbild und den Stil der Elemente aus, haben jedoch keinen Einfluss auf das Layout, z. B. die Hintergrundfarbe. Man nennt es Neuzeichnen.
Hinweis: Reflow führt definitiv zu einem Neuzeichnen, aber ein Neuzeichnen führt nicht unbedingt zu einem Reflow.
Wenn ein Reflow auftritt:
Reflow ist erforderlich, wenn sich das Seitenlayout und die geometrischen Eigenschaften ändern. Der Browser-Reflow erfolgt unter folgenden Umständen:
Das Hinzufügen oder Löschen sichtbarer DOM-Elemente ändert sich das Element ändert sich – Ränder, Abstände, Ränder, Breite und Höhe
4. Inhaltsänderungen – wie berechnete Wertänderungen in der Breite und Höhe, die durch Textänderungen oder Bildgrößenänderungen verursacht werden
5. Initialisierung der Seitendarstellung ;
6. Die Größe des Browserfensters ändert sich – wenn das Größenänderungsereignis auftritt;
Sehen wir uns an, wie sich der folgende Code auf Reflow und Neuzeichnen auswirkt:
Apropos: Jeder weiß, dass Reflow teurer ist als Neuzeichnen. Die Kosten für Reflow hängen davon ab, wie viele Knoten im Renderbaum neu erstellt werden müssen der Körper, es wird dazu führen, dass der gesamte Renderbaum neu fließt, was natürlich teurer ist, aber wenn Sie ein Element nach dem Körper einfügen, hat dies keinen Einfluss auf den Reflow des vorherigen Elementsvar s = document.body.style; s.padding = "2px"; // 回流+重绘 s.border = "1px solid red"; // 再一次 回流+重绘 s.color = "blue"; // 再一次重绘 s.backgroundColor = "#ccc"; // 再一次 重绘 s.fontSize = "14px"; // 再一次 回流+重绘// 添加node,再一次 回流+重绘 document.body.appendChild(document.createTextNode('abc!'));
Aus dem vorherigen Beispielcode können Sie ersehen, dass ein paar Zeilen einfachen JS-Codes etwa 6 Reflows und Neuzeichnungen verursachten. Und wir wissen auch, dass die Kosten für den Reflow nicht gering sind. Wenn jeder JS-Vorgang neu geflossen und neu gezeichnet werden muss, kann der Browser dies möglicherweise nicht ertragen. Daher optimieren viele Browser diese Vorgänge. Wenn die Vorgänge in der Warteschlange eine bestimmte Anzahl oder ein bestimmtes Zeitintervall erreichen, wird der Browser in die Warteschlange gestellt gespült und eine Charge verarbeitet. Dadurch werden mehrere Reflows und Neuzeichnungen zu einem Reflow und Neuzeichnungsvorgang. Obwohl es Browseroptimierungen gibt, kann es vorkommen, dass ein Teil des von uns geschriebenen Codes den Browser dazu zwingt, die Warteschlange im Voraus zu leeren, sodass die Browseroptimierung möglicherweise nicht effektiv ist. Wenn Sie einige Stilinformationen vom Browser anfordern, leert der Browser die Warteschlange, z. B.:
offsetTop, offsetLeft, offsetWidth, offsetHeight scrollTop/Left/Width/Height clientTop/Left/Width/Height width,height 请求了getComputedStyle(), 或者 IE的 currentStyle
减少回流、重绘 其实就是需要减少对 render tree 的操作(合并多次多DOM和样式的修改),并减少对一些style信息的请求,尽量利用好浏览器的优化策略。具体方法有:
直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器)
// 不好的写法var left = 1;var top = 1; el.style.left = left + "px"; el.style.top = top + "px";// 比较好的写法el.className += " className1";// 比较好的写法el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
让要操作的元素进行”离线处理”,处理完后一起更新
a) 使用 DocumentFragment 进行缓存操作,引发一次回流和重绘;
b) 使用 display:none 技术,只引发两次回流和重绘;
c) 使用 cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
3.不要经常访问会引起浏览器 flush 队列的属性,如果你确实要访问,利用缓存
// 别这样写,大哥 for(循环) { el.style.left = el.offsetLeft + 5 + "px";el.style.top = el.offsetTop + 5 + "px";} // 这样写好点 var left = el.offsetLeft, top = el.offsetTop, s = el.style; for (循环) { left += 10; top += 10; s.left = left + "px"; s.top = top + "px"; }
让元素脱离动画流,减少回流的Render Tree的规模
$("#block1").animate({left:50}); $("#block2").animate({marginLeft:50});
实例测试
最后用2个工具对上面的理论进行一些测试,分别是:dynaTrace(测试ie),Speed Tracer(测试Chrome)。
第一个测试代码不改变元素的规则,大小,位置。只改变颜色,所以不存在回流,仅测试重绘,代码如下:
<body> <script type="text/javascript"> var s = document.body.style; var computed; if (document.body.currentStyle) { computed = document.body.currentStyle; } else { computed = document.defaultView.getComputedStyle(document.body, ''); } function testOneByOne(){ s.color = 'red';; tmp = computed.backgroundColor; s.color = 'white'; tmp = computed.backgroundImage; s.color = 'green'; tmp = computed.backgroundAttachment; } function testAll() { s.color = 'yellow'; s.color = 'pink'; s.color = 'blue'; tmp = computed.backgroundColor; tmp = computed.backgroundImage; tmp = computed.backgroundAttachment; } </script> color test <br /> <button onclick="testOneByOne()">Test One by One</button> <button onclick="testAll()">Test All</button></body>
testOneByOne 函数改变3次color,其中每次改变后调用getComputedStyle,读取属性值(按我们上面的讨论,这里会引起队列的 flush),testAll 同样是改变3次color,但是每次改变后并不马上调用getComputedStyle。
我们先点击Test One by One按钮,然后点击 Test All,用dynaTrace监控如下:
上图可以看到我们执行了2次button的click事件,每次click后都跟一次rendering,2次click函数执行的时间都差不多, 0.25ms,0.26ms,但其后的rendering时间就相差一倍多。(其实很多时候,前端的性能瓶颈并不在于JS的执行,而是在于页面的呈现,这种情况在富客户端中更为突出)。我们再看图的下面部分,这是第一次rendering的详细信息,可以看到里面有2行是 Scheduleing layout task,这个就是我们前面讨论过的浏览器优化过的队列,可以看出我们引发2次的flush。
再看第二次rendering的详细信息,可以看出并没有Scheduleing layout task,所以这次rendering的时间也比较短。
测试代码2:这个测试跟第一次测试的代码很类似,但加上了对layout的改变,为的是测试回流。
<script type="text/javascript"> var s = document.body.style; var computed; if (document.body.currentStyle) { computed = document.body.currentStyle; } else { computed = document.defaultView.getComputedStyle(document.body, ''); } function testOneByOne(){ s.color = 'red'; s.padding = '1px'; tmp = computed.backgroundColor; s.color = 'white'; s.padding = '2px'; tmp = computed.backgroundImage; s.color = 'green'; s.padding = '3px'; tmp = computed.backgroundAttachment; } function testAll() { s.color = 'yellow'; s.padding = '4px'; s.color = 'pink'; s.padding = '5px'; s.color = 'blue'; s.padding = '6px'; tmp = computed.backgroundColor; tmp = computed.backgroundImage; tmp = computed.backgroundAttachment; } </script> color test <br /> <button onclick="testOneByOne()">Test One by One</button> <button onclick="testAll()">Test All</button>
这图可以看出,有了回流后,rendering的时间相比之前的只重绘,时间翻了3倍了,可见回流的高成本性啊。
大家看到时候注意明细处相比之前的多了个 Calcalating flow layout。
最后再使用Speed Tracer测试一下,其实结果是一样的,只是让大家了解下2个测试工具:
测试1:
图上第一次点击执行2ms (其中有50% 用于style Recalculation), 第二次1ms,而且第一次click后面也跟了2次style Recalculation,而第二次点击却没有style Recalculation。
但是这次测试发现paint重绘的时间竟然是一样的,都是3ms,这可能就是chrome比IE强的地方吧。
测试2:
从图中竟然发现第二次的测试结果在时间上跟第一次的完全一样,这可能是因为操作太少,而chrome又比较强大,所以没能测试明显结果出来。
但注意图中多了1个紫色部分,就是layout的部分。也就是我们说的回流。
Das obige ist der detaillierte Inhalt vonOptimierungsmethoden für das Neuzeichnen und Umfließen von Seiten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!