不确定是否有解决此问题的方法。我想知道是否有办法检测浏览器实际何时更新用户界面。
假设我想在运行长时间运行的同步代码块之前向元素添加一个类,在同步函数运行之后,该类将被删除。
el.classList.add('waiting');
longRunningSynchronousTask();
el.classList.remove('waiting');
如果我运行此代码,那么长时间运行的任务将启动,并在添加类之前阻止UI。我尝试使用MutationObserver
并使用getComputedStyle
检查元素,但这不起作用,因为那些不会反映实时更新UI的时间。
使用worker可能是最好的解决方案(在工作程序中删除长时间运行的代码,并在完成删除类时发布消息)。由于需要支持较旧的浏览器,这不是我的选择。
在实现工作者之外工作的唯一解决方案是使用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');
});
});
&#13;
.target {
height: 100px;
width: 100px;
background-color: gray;
}
.waiting {
background-color: red;
}
&#13;
<div class="target">
target
</div>
&#13;
答案 0 :(得分:0)
I believe requestIdleCallback is what You are looking for.
In the same way that adopting requestAnimationFrame allowed us to schedule animations properly and maximize our chances of hitting 60fps, requestIdleCallback will schedule work when there is free time at the end of a frame, or when the user is inactive.
Sadly, it's an experimental feature and is supported in Chrome Canary only.