如何对强制重排的 Javascript 操作进行分组?
Posted
技术标签:
【中文标题】如何对强制重排的 Javascript 操作进行分组?【英文标题】:How can I group Javascript actions that force reflow? 【发布时间】:2021-10-11 00:11:15 【问题描述】:我有一个项目负责管理元素的渲染,但我遇到了性能问题,替换元素然后专注于之前关注的内容。
以下是复制性能问题的最小示例:
const renderPage = () =>
// get the old section element
const oldSection = document.querySelector('section')
// create a new section element (we'll replaceWith later)
const newSection = document.createElement('section')
// create the render button
const newButton = document.createElement('button')
newButton.innerhtml = 'Render Page'
newButton.onclick = renderPage
newSection.appendChild(newButton)
// create a bunch of elements
const dummyDivs = [...new Array(100000)].forEach(() =>
const dummy = document.createElement('div')
dummy.innerHTML = 'dummy'
newSection.appendChild(dummy)
)
// replace the old page with the new one (causes forced reflow)
oldSection.replaceWith(newSection)
// reattach focus on the button (causes forced reflow)
newButton.focus()
window.renderPage = renderPage
<section>
<button onclick="renderPage()">Render</button>
</section>
在本地运行时,我在 Chrome/Edge 的性能报告中看到以下内容
replaceWith
和 focus
都在触发强制回流。有没有办法对这些操作进行批处理或分组,以便只发生一次回流?我意识到根本没有办法真正解决这种情况,但如果我可以批量处理它们,我认为这可能会提高我的性能。
【问题讨论】:
【参考方案1】:确实,焦点总是会导致回流:What forces layout / reflow
所以你可以做的是通过独立插入新按钮来减少回流时间,启动焦点,然后你可以附加其他孩子:
工作示例:Example
const renderPage = () =>
// get the old section element
const oldSection = document.querySelector('section')
// create a new section element (we'll replaceWith later)
const newSection = document.createElement('section')
// create the render button
const newButton = document.createElement('button')
newButton.innerHTML = 'Render Page'
newButton.onclick = renderPage
newSection.appendChild(newButton)
// create a bunch of elements
const dummies = []; // store in seperate array
const dummyDivs = [...new Array(100000)].forEach(() =>
const dummy = document.createElement('div')
dummy.innerHTML = 'dummy';
dummies.push(dummy)
)
// insert new section only with new button
oldSection.replaceWith(newSection)
newButton.focus(); // always causes reflow; but fast because it's only one element
// store all other nodes after focus
newSection.append(...dummies)
window.renderPage = renderPage
【讨论】:
感谢@coyer,这利用了渲染按钮始终位于顶部这一事实,在我的情况下从技术上讲这不是真的,但我没有理由不能拆分DOM 分为可聚焦事物之前、可聚焦事物和可聚焦事物之后。这可能比我想要的更符合逻辑,但这是我能弄清楚的。 奇怪的是,我注意到两个示例的运行时间大致相同。您在运行时是否注意到重大变化?它不再有“强制回流可能是性能瓶颈。”,所以显然有些不同(并且在没有更好的答案的情况下,值得被接受),但我很好奇这是否只是不触发警告由于一些技术性问题。 我只测量了附加和聚焦新节点的时间,这在我的示例中几乎快了两倍,并且还检查了只有预期的小回流和较大的回流来完全回流。以上是关于如何对强制重排的 Javascript 操作进行分组?的主要内容,如果未能解决你的问题,请参考以下文章