天天看点

(译)如何在webkit中触发(避免)重排

原文地址:How (not) to trigger a layout in WebKit

正如大多数web开发者所知道的,大量的js脚本运行时间可能都耗费在DOM的操作上,而这些操作执行太耗时是由执行脚本引起的,而不是编译执行js字节码本身所导致。这其中一个潜在的耗时操作就是重排(又名回流)-- 浏览器在渲染页面的过程中会执行从页面的DOM树来构造一个渲染树。DOM数量越多结构越复杂,操作越耗时。

让页面渲染和执行保持流畅的一个有效方法是进行批处理操作,让DOM的操作、处理和状态查询区分开来(译者注:状态查询就是获取DOM的一些样式属性值,如获取一个DIV元素的高度、宽度等)。

下面有些例子:

// 非最优, 会造成2次重排
var newWidth = aDiv.offsetWidth + 10; // Read
aDiv.style.width = newWidth + 'px'; // Write
var newHeight = aDiv.offsetHeight + 10; // Read
aDiv.style.height = newHeight + 'px'; // Write

// 更优,只引起一次重排
var newWidth = aDiv.offsetWidth + 10; // Read
var newHeight = aDiv.offsetHeight + 10; // Read
aDiv.style.width = newWidth + 'px'; // Write
aDiv.style.height = newHeight + 'px'; // Write
           

Stoyan Stefanov在其博客 Rendering: repaint, reflow/relayout, restyle中提供了关于这个话题的很好的例子。

这通常会导致开发者有这样的疑问:到底什么会触发重排?上周的时候, Dimitri Glazkov 在 this codesearch link这篇文章中回答了这个问题。我自己为了更好地去理解这个问题,我通读了这篇文章,并把文章总结成了一系列的属性和方法。

它们是:

元素(Element)

clientHeight, clientLeft, clientTop, clientWidth, focus(), getBoundingClientRect(), getClientRects(), innerText, offsetHeight, offsetLeft, offsetParent, offsetTop, offsetWidth, outerText, scrollByLines(), scrollByPages(), scrollHeight, scrollIntoView(), scrollIntoViewIfNeeded(), scrollLeft, scrollTop, scrollWidth

框架(Frame), 图片(Image)

height, width

范围(Range)

getBoundingClientRect(), getClientRects()

SVGLocatable

computeCTM(), getBBox()

SVGTextContent

getCharNumAtPosition(), getComputedTextLength(), getEndPositionOfChar(), getExtentOfChar(), getNumberOfChars(), getRotationOfChar(), getStartPositionOfChar(), getSubStringLength(), selectSubString()

SVGUse

instanceRoot

window

getComputedStyle(), scrollBy(), scrollTo(), scrollX, scrollY, webkitConvertPointFromNodeToPage(), webkitConvertPointFromPageToNode()

这个列表覆盖范围可能不全,但它是研究如何避免重排的一个好的开始。检查是否触发重排最好的方法是在Chrome或safari开发者工具的 Timeline panel选项中查看紫色布局条的状态。