违反长时间运行的JavaScript任务花费了xx毫秒


330

最近,我得到了这种警告,这是我第一次得到警告:

[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

您在哪里看到此警告?您没有说您正在使用哪种环境。假设使用某种浏览器,但使用哪种浏览器?
萨米·库莫宁

3
@SamiKuhmonen抱歉,我已经更新了我的问题。我用的是Chrome。我没有在Edge上找到任何类似的错误。
procatmer '16

8
我只是想补充一下,由于您可能已在Chrome中安装了任何扩展程序,因此也可能会出现此警告消息(2016年末推出)。通过在私有模式下进行测试很容易检查。
费尔

1
单击右侧链接(指示您发生冲突的脚本),将您带到代码中发生冲突的地方。
bluehipy

我正在使用Ionic 4(Angular 8),我的代码工作正常,突然开始出现这种违规行为-现在我的列表中没有显示数据?
卡皮尔·拉格万希

Answers:


278

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

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

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

我认为您更新到Chrome 56的可能性更高。我认为,此警告是一个了不起的新功能,如果您不顾一切,请仅将其关闭,并且评估师会从您身上夺走分数。其他浏览器中存在潜在的问题,但是浏览器并没有告诉您有问题。Chromium票在这里,但实际上没有任何有趣的讨论。

这些消息是警告而不是错误,因为它实际上不会引起重大问题。否则可能会导致框架掉落或造成不流畅的体验。

但是,值得进行调查和修复以提高应用程序的质量。为此,请注意消息出现在什么情况下,并进行性能测试以缩小问题发生的范围。开始性能测试的最简单方法是插入一些如下代码:

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的分析器,或使用像这样的基准测试库。

找到花费很长时间的代码(Chrome的阈值为50ms)后,您可以选择以下两种方法:

  1. 删掉一些不必要的任务
  2. 弄清楚如何更快地完成相同的任务
  3. 将代码分为多个异步步骤

(1)和(2)可能很困难或不可能,但有时确实很容易,应该是您的第一次尝试。如果需要,应该总是可以这样做(3)。为此,您将使用类似:

setTimeout(functionToRunVerySoonButNotNow);

要么

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

您可以在此处阅读有关JavaScript的异步特性的更多信息。


16
只是一个建议,而不是使用performance.now(),你可以使用console.timedeveloper.mozilla.org/en-US/docs/Web/API/Console/timeconsole.time('UniquetLabelName') ....code here.... console.timeEnd('UniqueLabelName')
denislexic

@denislexic我猜是这样。我不确定到底会增加什么价值。我认为,了解获取当前时间并以此为基础的基本操作更有价值。
voltrevo

34
好答案,沃尔沃!我的问题是,如果这样的代码是违反的,它到底违反了什么?Google必须采用某种标准,但是该标准是否在任何地方公开记录?
Bungler

1
@Bungler Dunno,我想知道是否也有一些指导原则。
voltrevo

3
@Bungler我只能猜到这是在说动画的代码违反了每秒至少提供60帧的帧,因此给用户带来不好的体验。。
user895400 '18

90

所有人都提到这些只是警告。但是,如果您想解决这些问题(应该这样做),则需要首先确定引起警告的原因。没有任何理由可以得到强制回流警告。有人为某些可能的选项创建了一个列表。您可以按照讨论获取更多信息。
这是可能原因的要点:

是什么促使布局/回流

当在JavaScript中请求/调用以下所有以下属性或方法时,将触发浏览器同步计算样式和布局*。这也称为重排或布局颠簸,这是常见的性能瓶颈。

元件

盒子指标
  • 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() 可以触发双重强制布局(来源
也…
  • elem.computedRoleelem.computedName
  • elem.innerText来源

getComputedStyle

window.getComputedStyle()通常会强制样式重新计算(

window.getComputedStyle() 如果以下任一情况成立,也会强制布局:

  1. 元素在阴影树中
  2. 有媒体查询(与视口有关的查询)。具体而言,执行以下操作之一:()* min-widthmin-heightmax-widthmax-heightwidthheight * aspect-ratiomin-aspect-ratiomax-aspect-ratio
    • device-pixel-ratioresolutionorientation
  3. 请求的属性是以下之一:(source
    • heightwidth * toprightbottomleft * margin[ -top-right-bottom-left,或速记 ]仅当余量是固定的。* padding[ -top-right-bottom-left,或速记 ]仅当填充是固定的。* transformtransform-originperspective-origin * translaterotatescale * webkit-filterbackdrop-filter * motion-pathmotion-offsetmotion-rotation * xyrxry

窗口

  • window.scrollXwindow.scrollY
  • window.innerHeightwindow.innerWidth
  • window.getMatchedCSSRules() 唯力风格

形式

  • inputElem.focus()
  • inputElem.select()textareaElem.select()来源

鼠标事件

  • mouseEvt.layerXmouseEvt.layerYmouseEvt.offsetXmouseEvt.offsetY

文献

  • doc.scrollingElement 唯力风格

范围

  • range.getClientRects()range.getBoundingClientRect()

SVG

内容可编辑

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

在这里查看更多。

此外,这是原始发行版的Chromium源代码,以及有关警告的性能API讨论


编辑:还有一篇文章,介绍如何在Google的PageSpeed Insight上最大程度地减少布局重排。它解释了什么是浏览器重排:

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

另外,它说明了如何最小化它:

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

1
更多背景知识:原始问题的Chromium源代码以及有关警告的性能API讨论
robocat

1
根据上述内容,只需读取element.scrollTop即可触发重排。这让我感到反常。我可以理解为什么设置 element.scrollTop会触发重排,而只是读取其值?如果确实如此,有人可以进一步解释为什么会这样吗?
David Edwards

29

一些想法:

  • 删除一半的代码(也许通过注释掉)。

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

    • 问题不在那里吗?好吧,看看您评论的一半!

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


谢谢您的回答。我确实删除了一半,甚至从项目中排除了我的主要.js文件。不知何故错误仍然发生。这就是为什么我对此感到沮丧。是的,我正在使用git。我今天才意识到这个错误。自从成为小组项目以来,已经进行了很多提交工作。可能会进行深入检查。再次感谢您的想法。
procatmer '16

@procatmer使用相同的策略来查找git commit。例如,如果我有10次提交(A,B,C,D,E,F,G,H,I,J),其中A是最旧的,那么我想git checkout E看看问题是否已经存在。如果是,我将在提交的前半部分继续寻找问题。否则,我将在下半年寻找问题。
therobinkim '16

1
@procatmer另外,如果您省略了主.js文件并且问题仍然存在...则可能是您通过<script src="...">标签引入的库!也许有些事情不值得担心(特别是因为这只是警告)?
therobinkim '16

1
我终于找到了问题所在。我用您的第二个想法来跟踪更改。是的,问题来自外部.js文件。显然,这确实很重要。这会使我的网站变慢。无论如何,再次感谢您的回答和想法。
procatmer '16

2
您可以使用git bisect来应用二进制搜索。我认为这只是为了发现错误。
pietrovismara

12

为了确定问题的根源,请运行您的应用程序,并将其记录在Chrome的“性能”标签中

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

检查这些文件,然后尝试确定这是扩展名还是您的扩展名。(如果是您的,那么您已找到问题的根源。)


不,我没有AdBlock,但仍然可以在控制台中找到它。
NikolaStojaković17年

尝试使用“性能”选项卡对其进行分析,并查找长时间运行的功能的来源。可以是任何东西,但这是识别问题根源的潜在方法。
马特·莱昂诺维兹

6

在“网络”标签下的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文件。

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

我最好的猜测是,这些Angular插件正在递归地查找DOM的越来越深的部分作为开​​始标签-没有找到它们,它们在退出前就必须遍历整个DOM,这比Chrome期望的时间更长-因此发出了警告。


6

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

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毫秒: 铬性能分析器布局重新计算重排

现在:

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毫秒: 铬探伤剂暗

而且我认为搜索现在可以更快地进行(229个节点)。


3
总之,通过收到违规,您可以优化代码,并且现在性能更好。
不是用户的用户,

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
});

插入此技巧代码后,所有警告消息均消失。



2

如果您使用的是Chrome Canary(或Beta),则只需选中“隐藏违规”选项即可。

在Chrome 56控制台中隐藏违规复选框


1

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

错误消息示例:

警告的屏幕截图

说明:

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

原始文章:UX开发人员Lindsey Simon发表在developers.google.com上,以最大程度地减少浏览器的重排

这是链接谷歌Chrome提供了性能分析器,在布局轮廓(紫红色地区),关于警告的详细信息。


0

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

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

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

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

一切都很好,直到我更新了迫使“结果组件”重新呈现的“状态”。这里的主要问题是我在同一渲染器(App.js / return ..)中有一个material-ui主题(https://material-ui.com/customization/theming/#a-note-on-performance)。作为“结果组件”,SummaryAppBarPure

解决方案是将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 />
//...

-2

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

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

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

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

  1. 关闭1-by-1调用,然后重新加载代码以查看它是否仍然产生错误。
  2. 如果第二个脚本导致错误,请使用setTimeOut基于冲突持续时间的。

这不是解决方案。最好将其作为对原始问题的评论。
Paul-Sebastian Manole

-6

这不是错误,只是一条简单的消息。要执行此消息 ,请将
<!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为冗长。
解决方案


5
只是一些建议:您的答案与问题无关。修复或删除答案。问题是“为什么Chrome浏览器控制台显示违规警告”。答案是,这是较新的Chrome浏览器中的一项功能,如果网页在执行JS时导致过多的浏览器重排,它会警告您。请从Google参考此资源以获取更多信息。
Paul-Sebastian Manole
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.