是否可以在浏览器中检测重绘/重排

Is it possible to detect repaint/reflow in the browser?

本文关键字:重排 检测 浏览器 是否      更新时间:2023-09-26

不确定是否有解决此问题的方法。我想知道是否有办法检测浏览器何时实际更新 UI。

假设我想在运行长时间运行的同步代码块之前向元素添加一个类,在同步函数运行之后,该类将被删除。

el.classList.add('waiting');
longRunningSynchronousTask();
el.classList.remove('waiting');

如果我运行此代码,长时间运行的任务将启动,并在添加类之前阻止 UI。我尝试使用 MutationObserver 的,并使用 getComputedStyle 检查元素,但这不起作用,因为这些不会反映实时更新 UI 的时间。

使用工作线程

可能是最好的解决方案(删除工作线程中长时间运行的代码,并在完成后发布消息以删除类)。这不是我真正的选择,因为需要支持较旧的浏览器。

在实现工作线程之外唯一有效的解决方案是使用 setTimeout .我很想知道是否有人遇到过这个问题,以及是否有任何方法可以在浏览器中检测 UI 的重绘/重排。

请参阅我的示例以更好地说明问题。

const el = document.querySelector('.target');
const isRed = c => c === 'red' || 'rgb(255, 0, 0)';
let classActuallyApplied = false;
let requestId;
const longRunningTask = (mil, onComplete) => {
  if (classActuallyApplied) {
    cancelAnimationFrame(requestId);
    var start = new Date().getTime();
    while (new Date().getTime() < start + mil);
    onComplete();
  } else {
     requestId = requestAnimationFrame(longRunningTask.bind(null, mil, onComplete));
  }
}
const observer = new MutationObserver(function(mutations) {
	classActuallyApplied = mutations
  	.filter(mutation => {
			return mutation.type === 'attributes' &&
      	mutation.attributeName === 'class' &&
        mutation.target.classList.contains('waiting');
		}).length > 0;
});
const observerConfig = {
	attributes: true, 
	childList: false, 
	characterData: false 
};
observer.observe(el, observerConfig);
el.addEventListener('click', e => {
	el.classList.add('waiting');
  longRunningTask(1000 * 5, () => {
  	// el.classList.remove('waiting');
  });
});
.target {
  height: 100px;
  width: 100px;
  background-color: gray;
}
.waiting {
  background-color: red;
}
<div class="target">
  target
</div>

我相信requestIdleCallback就是你要找的。

2016 developers.google.com 日起:

就像

采用requestAnimationFrame允许我们正确调度动画并最大限度地提高达到60fps的机会一样,requestIdleCallback将在帧末尾有空闲时间或用户处于非活动状态时安排工作。

这是一项实验性功能,但(截至 2021 年 3 月)大多数现代浏览器都支持此功能。请参阅 MDN 兼容性表和 caniuse.com。