gpt4 book ai didi

javascript - 回调中未触发回流/布局?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:40:50 25 4
gpt4 key购买 nike

基于这个问题:How do I know the IntersectionObserver scroll direction?

我试图在可观察的回调中重现一些布局/回流案例,但我做不到,所以我试图简化用例并最终问了这个问题。

我正在阅读 Paul Irish 的要旨 what-forces-layout.md我的问题很简单。

在 body 元素上没有回调的情况下肯定会触发布局,请参见下面的示例:

element.focus() triggers layout

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text">
<script type="text/javascript">
var elementB = document.querySelector('input');

elementB.focus();
</script>
</body>
</html>

see chrome performance record

但如果将 focus 事件包装在点击回调中,则不会触发布局/重排。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text">
<script type="text/javascript">
var elementB = document.querySelector('input');

function onClick() {
elementB.focus();
}

document.addEventListener('click', onClick);
</script>
</body>
</html>

see chrome performance record

这就是我的问题,为什么不触发布局/回流?

最佳答案

我不确定我是否答对了您的问题,但在情况 1 中,当解析器开始执行脚本时,DOMContentLoaded 尚未触发,它仍在解析文档的其余部分。同时,您在 elemB 上调用 focus,您会立即触发布局流。

在情况 2 中,除非您单击文档本身,否则根本不会调用 onClick 函数。您可以通过在您提供的 fiddle 上打开“Paint Flashing” 来验证这一点。只有当您单击时,输入才会变为绿色。

而在第一种情况下,您会在开始时看到输入的短暂闪烁(即您对 .focus 的调用),然后是整个 documentElement(在 DOMContentLoaded)。

在第二种情况下,您只有整个 documentElement 闪烁一次(在 DOMContentLoaded 上,前提是没有其他任何东西触发回流/重绘 onload 事件),然后每次点击只有输入元素闪烁一次。

附言:

现在据我所知,我已经在我的本地机器上尝试了您的 2 个案例,有趣的是,在您的第一个案例中,我在 DOMContentLoaded 之后看到了 2 layout 事件。

但是,如果我从您的案例 1 中注释掉行 elementB.focus(); 并再次记录,我会再次看到 2 布局事件

根据我的理解,浏览器将在开始时执行 2 次布局操作,一旦它开始解析正文,然后一次围绕 DOMContentLoaded。并且如果任何同步强制布局垃圾处理是由 javascript 完成的(通过调用链接中列出的任何方法/属性),浏览器将尝试批处理这些操作。

为了测试这个行为,我修改了你的第一个案例如下:

!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text" style="position:relative;top:0px;">
<script type="text/javascript">
var elementB = document.querySelector('input');
elementB.focus();
</script>
<script async="true">
setTimeout(function(){
elementB.style.top = parseInt(elementB.style.top) + 5 + "px";
},500)
</script>
</body>
</html>

现在会发生的是,您将在加载事件后(~500 毫秒)立即拥有第三个布局事件(不需要异步)。但是,如果您要使 setTİmeout 0ms,您将再次获得2 个布局事件! (微任务队列行为可能无法保证,如果你看到 3 种布局,强制同步布局,删除 async 属性和 setTimeout 包装在第二个脚本标签内)。 底线:因此浏览器对其进行了批处理,或者至少这是我从这个示例中看到的。

对于你的第二种情况,当我按照你发布的方式记录它时,我没有看到布局事件(2 布局和以前一样)是正确的。但我看到的是每次事件后一致的样式重新计算+更新布局树+绘画。这让我觉得一旦布局树被更新,如果布局垃圾不是必要的,它就不会被重新计算。为了测试该行为,我更改了您的第二个脚本,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text" style="position:relative;top:0px;">
<script type="text/javascript">
var elementB = document.querySelector('input');

function onClick() {
elementB.focus();
elementB.style.top = parseInt(elementB.style.top) + 5 + "px";
}

document.addEventListener('click', onClick);
</script>
</body>
</html>

这里每点击一次文档,输入框就会向下移动5个像素。如果您在 10 秒内记录多次点击事件,您也会看到很多更新布局树 + 重绘和布局垃圾。这让我觉得布局垃圾是在更新布局树之后完成的,如果只需要的话。

结论(我可能大错特错)

  • 浏览器将在解析 HTML 期间尝试批处理布局事件。
  • element.focus 将触发重绘 + 更新布局树,但不能保证布局垃圾(至少从这些例子中)

关于javascript - 回调中未触发回流/布局?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49801866/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com