Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/google-chrome/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 回拨中是否未触发回流/布局?_Javascript_Google Chrome_Google Chrome Devtools_Reflow_Web Performance - Fatal编程技术网

Javascript 回拨中是否未触发回流/布局?

Javascript 回拨中是否未触发回流/布局?,javascript,google-chrome,google-chrome-devtools,reflow,web-performance,Javascript,Google Chrome,Google Chrome Devtools,Reflow,Web Performance,基于这个问题: 我试图在可观察的回调中重现一些布局/回流案例,但我做不到,所以我试图简化用例并最终提出这个问题。 我在读保罗·爱尔兰的要点,我的问题很简单 如果输入在body元素上没有回调,则肯定会触发布局,请参见下面的示例: 文件 var elementB=document.querySelector('input'); 元素b.focus(); 我不确定您的问题是否正确,但在案例1中,当解析器开始执行脚本时,DOMContentLoaded尚未启动,它仍在解析文档的其余部分。同时,您在

基于这个问题

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

我在读保罗·爱尔兰的要点,我的问题很简单

如果输入在body元素上没有回调,则肯定会触发布局,请参见下面的示例:


文件
var elementB=document.querySelector('input');
元素b.focus();

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

在案例2中,除非单击文档本身,否则根本不会调用
onClick
函数。您可以通过打开您提供的小提琴上的“油漆闪烁”来验证这一点。只有单击时,输入才会变为绿色

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

在第二种情况下,整个documentElement只闪烁一次(在DOMContentLoaded上,前提是没有其他触发reflow/repain onload事件),然后每次单击只闪烁一次输入元素

附言: 现在,据我所知,我已经在我的本地机器上试用了您的两个案例,有趣的是,在您的第一个案例中,我在加载domcontents后立即看到了2layout活动

但是,如果我注释掉行
elementB.focus()并再次记录,我再次看到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>
<!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>
!DOCTYPE html>
文件
var elementB=document.querySelector('input');
元素b.focus();
setTimeout(函数(){
elementB.style.top=parseInt(elementB.style.top)+5+“px”;
},500)
现在将要发生的是,在加载事件之后(~500ms),您将有一个第三个布局活动(不需要异步)。但是,如果您要使setTİmeout0毫秒,您将再次获得2个布局活动!(如果看到3个布局,可能无法保证微任务队列行为,要强制同步布局,请删除async属性和第2个脚本标记内的setTimeout wrap)底线:所以浏览器会对其进行批处理,或者至少这是我在本例中看到的

对于您的第二个案例,当我以您发布的方式记录它时,我没有看到布局活动是正确的(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');
    elementB.focus();
  </script>
  <script async="true">
    setTimeout(function(){
        elementB.style.top = parseInt(elementB.style.top) + 5 + "px";
    },500)
  </script>
</body>
</html>
<!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>

文件
var elementB=document.querySelector('input');
函数onClick(){
元素b.focus();
elementB.style.top=parseInt(elementB.style.top)+5+“px”;
}
document.addEventListener('click',onClick);
在这里,每次单击文档时,输入框将向下移动5个像素。如果在10秒内记录多个单击事件,您将看到大量的更新布局树+重新绘制和布局破坏。这让我觉得布局垃圾是在更新布局树之后完成的,如果必要的话

结论(我可能大错特错)
  • 在解析HTML期间,浏览器将尝试批处理布局活动
  • element.focus将触发重绘+更新布局树,但布局破坏不能保证(至少在这些示例中)

很难确定为什么开发工具在这种情况下没有注意到回流,这可能是因为布局没有变化,回流算法短路,开发工具忽略了回流。它也可能是别的东西

但回流会发生,至少在必要时是这样

为了测试回流,IMO最好的方法是触发需要它的东西,CSS转换就是这样一种东西

var input=document.querySelector('input');
//测试我们的逻辑,没有任何可能触发回流的东西
noreflow.onclick=函数(){
//从CSS中的20px开始
test.style.transition='none';
test.style.width='100px';//应忽略
test.style.transition='宽度1s线性';
test.style.width='20px';
//应该从20px到20px=>无转换
};
//手动触发回流焊测试
reflow.onclick=函数(){
//从CSS中的20px开始
test.style.transition='none';
test.style.width='100px';
input.focus();//回流
//现在应该计算为100px
test.style.transition='宽度1s线性';
test.style.width='20px';
//现在,这应该是行动了
}
#测试{
宽度:20px;
高度:20px;
背景:红色;
}

无回流 回流焊
我说的不是这个意思。当您不调用函数时,不会触发回流,这就是它的全部内容。如果您在任意位置执行elem.scrollTop,它将触发回流,但函数(){elem.scrollTop..}在调用之前不会触发回流。这就是为什么把它们包起来