违规长时间运行的JavaScript任务需要xx ms

时间:2016-12-19 08:29:07

标签: javascript google-chrome dom

最近,我收到了这样的警告,这是我第一次得到它:

  
[Violation] Long running JavaScript task took 234ms
[Violation] Forced reflow while executing JavaScript took 45ms

我正在开展一个小组项目,我不知道这是从哪里来的。这从未发生过。突然间,当其他人参与该项目时,它就出现了。如何找到导致此警告的文件/功能?我一直在寻找答案,但主要是关于如何解决它的解决方案。如果我甚至找不到问题的根源,我无法解决。

在这种情况下,警告仅出现在Chrome上。我尝试使用Edge,但我没有得到任何类似的警告,我还没有在Firefox上测试它。

我甚至从jquery.min.js收到错误:

  
[Violation] Handler took 231ms of runtime (50ms allowed)            jquery.min.js:2

15 个答案:

答案 0 :(得分:208)

更新:Chrome 58+默认隐藏了这些和其他调试消息。要显示它们,请单击“信息”旁边的箭头,然后选择“详细”。

默认情况下,Chrome 57启用了“隐藏违规”功能。要重新打开它们,您需要启用过滤器并取消选中“隐藏违规”框。

  

当其他人参与该项目时突然出现

我认为你更有可能更新到Chrome 56.这个警告是一个很棒的新功能,在我看来,如果你绝望而且你的评估员会从你那里拿走分数,请关闭它。其他浏览器存在潜在问题,但浏览器并没有告诉您存在问题。 Chromium票是here,但实际上没有任何有趣的讨论。

这些消息是警告而不是错误,因为它实际上不会导致重大问题。它可能会导致帧丢失或导致不太顺畅的体验。

然而,他们值得调查和修复以提高应用程序的质量。这样做的方法是关注消息出现的情况,并进行性能测试以缩小问题发生的位置。开始性能测试的最简单方法是插入一些代码:

function someMethodIThinkMightBeSlow() {
    const startTime = performance.now();

    // Do the normal stuff for this function

    const duration = performance.now() - startTime;
    console.log(`someMethodIThinkMightBeSlow took ${duration}ms`);
}

如果您想获得更高级的功能,还可以使用Chrome's profiler,或者使用this one之类的基准测试库。

一旦你发现一些需要很长时间的代码(50毫秒是Chrome的门槛),你有几个选择:

  1. 删除部分/全部可能不必要的任务
  2. 弄清楚如何更快地完成同样的任务
  3. 将代码划分为多个异步步骤
  4. (1)和(2)可能很难或不可能,但它有时很容易,应该是你的第一次尝试。如果需要,应始终可以做(3)。为此,您将使用以下内容:

    setTimeout(functionToRunVerySoonButNotNow);
    

    // This one is not available natively in IE, but there are polyfills available.
    Promise.resolve().then(functionToRunVerySoonButNotNow);
    

    您可以阅读有关JavaScript here的异步性质的更多信息。

答案 1 :(得分:61)

这些只是每个人都提到的警告。但是,如果您热衷于解决这些问题(您应该这样做),那么您需要首先确定导致警告的原因。没有任何理由可以获得强制回流警告。 有人为某些可能的选项创建了list。您可以按照讨论了解更多信息 以下是可能原因的要点:

  

什么强制布局/重排

     

请求/调用时的所有以下属性或方法   JavaScript,会触发浏览器同步计算   风格和布局*。这也称为reflow或layout thrashing,   并且是常见的性能瓶颈。

     

元素

     Box指标      
      
  • elem.offsetLeftelem.offsetTopelem.offsetWidthelem.offsetHeightelem.offsetParent
  •   
  • elem.clientLeftelem.clientTopelem.clientWidthelem.clientHeight
  •   
  • elem.getClientRects()elem.getBoundingClientRect()
  •   
     滚动的东西      
      
  • elem.scrollBy()elem.scrollTo()
  •   
  • elem.scrollIntoView()elem.scrollIntoViewIfNeeded()
  •   
  • elem.scrollWidthelem.scrollHeight
  •   
  • elem.scrollLeftelem.scrollTop也设置了
  •   
     焦点      
      
  • elem.focus()可以触发强制布局(source
  •   
     也…      
      
  • elem.computedRoleelem.computedName
  •   
  • elem.innerTextsource
  •   
     

的getComputedStyle

     

window.getComputedStyle()通常会强制重新设置样式   (source

     

window.getComputedStyle()也将强制布局,如果有的话   以下是真的:

     
      
  1. 元素位于影子树
  2.   
  3. 有媒体查询(与视口相关的查询)。具体来说,以下之一:   (source)* min-widthmin-heightmax-widthmax-heightwidthheight * aspect-ratiomin-aspect-ratiomax-aspect-ratio      
        
    • device-pixel-ratioresolutionorientation
    •   
  4.   
  5. 请求的属性是以下之一:(source)      
        
    • heightwidth * toprightbottomleft * margin [-top-right-bottom-left简写]   保证金是固定的。 * padding [-top-right-bottom-left,   或仅当填充是固定的时,简写]。 * transform,   transform-originperspective-origin * translaterotate,   scale * webkit-filterbackdrop-filter * motion-path,   motion-offsetmotion-rotation * xyrxry
    •   
  6.         

    窗口

         
        
    • window.scrollXwindow.scrollY
    •   
    • window.innerHeightwindow.innerWidth
    •   
    • window.getMatchedCSSRules()仅强制风格
    •   
         

    表单

         
        
    • inputElem.focus()
    •   
    • inputElem.select()textareaElem.select()source
    •   
         

    鼠标事件

         
        
    • mouseEvt.layerXmouseEvt.layerYmouseEvt.offsetXmouseEvt.offsetY   (source
    •   
         

    文档

         
        
    • doc.scrollingElement仅强制风格
    •   
         

    范围

         
        
    • range.getClientRects()range.getBoundingClientRect()
    •   
         

    SVG

               

    CONTENTEDITABLE

         
        
    • 很多&很多东西,......包括将图像复制到剪贴板(source
    •   

查看更多here

另外,这里是original issue的Chromium源代码和警告的discussion about a performance API

编辑:还有一篇关于如何最小化PageSpeed Insight by Google上的布局重排的文章。它解释了什么是浏览器重排:

  

Reflow是用于重新计算的Web浏览器进程的名称   出于此目的,文档中元素的位置和几何形状   重新呈现部分或全部文档。因为回流是一个   在浏览器中进行用户阻塞操作,对开发人员来说非常有用   了解如何提高回流时间,也了解如何   各种文档属性的影响(DOM深度,CSS规则   回流时间的效率,不同类型的风格变化。   有时可能需要回复文档中的单个元素   回流其父元素以及其后的任何元素。

此外,它解释了如何最小化它:

  
      
  1. 减少不必要的DOM深度。 DOM树中一个级别的更改   可以导致树的每个级别的更改 - 一直到最后   root,一直到修改后的节点的子节点。   这导致花费更多时间进行回流。
  2.   
  3. 最小化CSS规则,并删除未使用的CSS规则。
  4.   
  5. 如果您进行复杂的渲染更改(如动画),请执行此操作。使用position-absolute或position-fixed来完成   此。
  6.   
  7. 避免使用不必要的复杂CSS选择器 - 后代选择器   特别是 - 它需要更多的CPU能力来进行选择器匹配。
  8.   

答案 2 :(得分:26)

一些想法:

  • 删除一半代码(可能是通过评论)。

    • 问题仍然存在吗?太棒了,你已经缩小了可能性!重复。

    • 问题不存在吗?好的,看看你评论的那一半!

  • 您使用的是任何版本控制系统(例如Git)吗?如果是这样,git checkout您最近的一些提交。问题何时出现?查看提交以确定在问题首次到达时确切地更改了哪些代码。

答案 3 :(得分:8)

就我而言,我发现这实际上是由扩展程序中的代码引起的。对我来说,扩展名是AdBlock。

要确定问题的根源,请运行您的应用程序,并将其记录在Chrome的效果标签中。

在那里,您可以检查需要很长时间才能运行的各种功能。就我而言,与控制台中的警告相关联的是来自AdBlock扩展程序加载的文件,但在您的情况下这可能是其他内容。

检查这些文件并尝试确定这是否是某些扩展程序的代码或您的代码。 (如果是你的,那么你找到了问题的根源。)

答案 4 :(得分:5)

在“网络”标签下的Chrome控制台中查找最长时间加载的脚本。

在我的情况下,我已经包含但尚未在应用程序中使用的脚本上有一组Angular添加:

<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-utils/0.1.1/angular-ui-utils.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-animate.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-aria.min.js"></script>

这些是加载时间较长的JavaScript文件,而不是指定“长时间运行任务”错误的时间。

所有这些文件都在我的其他网站上运行而没有生成错误但是我在一个几乎没有任何功能的新网络应用程序上遇到了这个“长时间运行任务”错误。删除后错误立即停止。

我最好的猜测是,这些Angular附加组件正在逐渐向DOM的越来越深的部分寻找开始标记 - 找不到,他们必须在退出之前遍历整个DOM,这需要比Chrome预期更长的时间 - 因此警告

答案 5 :(得分:4)

这已添加到Chrome 56测试版中,即使它不是来自Chromium博客的此更改日志:Chrome 56 Beta: “Not Secure” warning, Web Bluetooth, and CSS position: sticky

您可以使用隐藏违规行为复选框在控制台的过滤栏中隐藏此内容。

答案 6 :(得分:3)

如果您使用的是Chrome Canary(或Beta),请选中“隐藏违规行为”选项。

Hide Violations Checkbox in Chrome 56 Console

答案 7 :(得分:3)

我在Apache Cordova源代码中找到了一个解决方案。 他们这样实现:

var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve();
var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); };

简单的实施,但聪明的方式。

在Android 4.4上,使用Promise。 对于旧版浏览器,请使用setTimeout()

用法:

nextTick(function() {
  // your code
});

插入此特技代码后,所有警告消息都消失了。

答案 8 :(得分:3)

我在我的代码中找到了此消息的根,搜索并隐藏或显示节点(离线)。这是我的代码:

search.addEventListener('keyup', function() {
    for (const node of nodes)
        if (node.innerText.toLowerCase().includes(this.value.toLowerCase()))
            node.classList.remove('hidden');
        else
            node.classList.add('hidden');
});

性能选项卡(探查器)显示大约60毫秒的事件: Chromium performance profiler layout recalculation reflow

现在:

search.addEventListener('keyup', function() {
    const nodesToHide = [];
    const nodesToShow = [];
    for (const node of nodes)
        if (node.innerText.toLowerCase().includes(this.value.toLowerCase()))
            nodesToShow.push(node);
        else
            nodesToHide.push(node);

    nodesToHide.forEach(node => node.classList.add('hidden'));
    nodesToShow.forEach(node => node.classList.remove('hidden'));
});

性能选项卡(探查器)现在显示大约1毫秒的事件: Chromium profiler dark

我觉得搜索现在运行得更快(229个节点)。

答案 9 :(得分:1)

在此添加我的见解,因为该主题是该主题的“转到” stackoverflow问题。

我的问题是在Material-UI应用程序中(早期)

  • 自定义主题提供程序的放置是原因

当我进行一些计算以强制呈现页面时 (一个组件“显示结果”取决于在其他“输入部分”中设置的内容)。

一切都很好,直到我更新了迫使“结果组件”重新呈现的“状态”。这里的主要问题是,我在与“结果组件” SummaryAppBarPure

相同的渲染器(App.js / return ..)中有一个Material-ui主题(https://material-ui.com/customization/theming/#a-note-on-performance)。

解决方案是将ThemeProvider提升一个级别(Index.js),并将App组件包装在此处,因此不会强制ThemeProvider重新计算和绘制/布局/重排。

之前

在App.js中:

  return (
    <>
      <MyThemeProvider>
      <Container className={classes.appMaxWidth}>

        <SummaryAppBarPure
//...

在index.js中

ReactDOM.render(
  <React.StrictMode>
      <App />
//...

之后

在App.js中:

return (
    <>
      {/* move theme to index. made reflow problem go away */}
      {/* <MyThemeProvider> */}
      <Container className={classes.appMaxWidth}>

        <SummaryAppBarPure
//...

在index.js中

ReactDOM.render(
  <React.StrictMode>
    <MyThemeProvider>
      <App />
//...

答案 10 :(得分:0)

这是Google Chrome浏览器的违规错误,在启用Verbose日志记录级别时显示。

错误消息示例:

screenshot of the warning

说明:

  

重排是Web浏览器进程的名称,用于重新计算文档中元素的位置和几何形状,以重新呈现部分或全部文档。由于重排是浏览器中的用户阻止操作,因此对于开发人员了解如何缩短重排时间以及了解各种文档属性(DOM深度,CSS规则效率,不同类型的样式更改)对重排的影响非常有用。时间。有时,重排文档中的单个元素可能需要重排其父元素以及紧随其后的所有元素。

原始文章:Minimizing browser reflow,由UX开发人员Lindsey Simon发表在developers.google.com上。

this is the link和Google Chrome浏览器可在Performance Profiler中的布局配置文件(淡紫色区域)上为您提供有关警告的更多信息。

答案 11 :(得分:0)

关于它的价值,这是我遇到

时的2分
[Violation] Forced reflow while executing JavaScript took <N>ms

警告。有问题的页面是根据用户内容生成的,因此我对DOM的大小影响不大。就我而言,问题是两列的表可能有数百行,甚至数千行。 (尚未实现按需行加载,抱歉!)

jQuery上,使用keydown可以选择一组行并切换其可见性。我注意到,与显式使用toggle()hide()相比,在该集合上使用show()更容易触发警告。

有关此特定性能情况的更多详细信息,另请参见this article

答案 12 :(得分:-1)

对于Chrome 57:

  1. 转到控制台

  2. 点击&#34;保存日志&#34;附近的过滤器图标复选框

  3. 勾选&#34;隐藏违规行为&#34;复选框以隐藏警告。

  4. Console

    对于Chrome 58 +:

    1. 转到控制台
    2. 在日志记录级别下拉列表中查看详细信息以查看违规行为,或取消选中该项以隐藏它。

答案 13 :(得分:-1)

当您在执行结束之前多次调用一个函数时,通常会发生强制重排。

例如,您可能在智能手机上遇到了问题,但在传统浏览器上却没有问题。

我建议使用setTimeout来解决问题。

这不是很重要,但是我重复一遍,问题是在多次调用一个函数时出现的,而不是在该函数花费超过50毫秒时出现的。我认为您的答案有误。

  1. 关闭1-by-1调用并重新加载代码以查看其是否仍然产生错误。
  2. 如果第二个脚本导致错误,请根据违规的持续时间使用setTimeOut

答案 14 :(得分:-1)

这不是错误,只是一条简单的消息。要执行此消息更改
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">(示例)

<!DOCTYPE html>(Firefox消息源对此期望)

该消息显示在Google Chrome 74和Opera 60中。更改后很明显,详细程度为0。
解决方法