最近,我收到了这样的警告,这是我第一次得到它:
[违规] 长时间运行 JavaScript 任务耗时 234ms [违规] 执行 JavaScript 时强制回流耗时 45ms
我正在做一个小组项目,我不知道这是从哪里来的。这以前从未发生过。突然,当其他人参与了该项目时,它出现了。如何找到导致此警告的文件/功能?我一直在寻找答案,但主要是关于如何解决它的解决方案。如果我什至找不到问题的根源,我就无法解决它。
在这种情况下,警告只会出现在 Chrome 上。我尝试使用 Edge,但没有收到任何类似的警告,而且我还没有在 Firefox 上测试过。
我什至收到来自 jquery.min.js
的错误:
[违规] 处理程序占用了 231 毫秒的运行时间(允许 50 毫秒)jquery.min.js:2
更新: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 这样的基准测试库。
一旦你发现了一些需要很长时间的代码(50ms 是 Chrome 的阈值),你有几个选择:
删除部分/全部可能不必要的任务 弄清楚如何更快地完成相同的任务 将代码分成多个异步步骤
(1)和(2)可能很难或不可能,但有时真的很容易,应该是你的第一次尝试。如果需要,应该始终可以执行 (3)。为此,您将使用以下内容:
setTimeout(functionToRunVerySoonButNotNow);
或者
// This one is not available natively in IE, but there are polyfills available.
Promise.resolve().then(functionToRunVerySoonButNotNow);
您可以阅读有关 JavaScript 的异步特性的更多信息here。
正如每个人都提到的,这些只是警告。但是,如果您热衷于解决这些问题(您应该这样做),那么您需要首先确定导致警告的原因。没有任何一个原因会导致您收到强制回流警告。有人为一些可能的选项创建了 list。您可以关注讨论以获取更多信息。
以下是可能原因的要点:
什么强制布局/重排以下所有属性或方法,当在 JavaScript 中请求/调用时,将触发浏览器同步计算样式和布局*。这也称为回流或布局抖动,是常见的性能瓶颈。元素框指标 elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight, elem.offsetParent elem.clientLeft, elem.clientTop, elem.clientWidth, elem.clientHeight elem.getClientRects(), elem.getBoundingClientRect() 滚动内容elem.scrollBy(), elem.scrollTo() elem.scrollIntoView(), elem.scrollIntoViewIfNeeded() elem.scrollWidth, elem.scrollHeight elem.scrollLeft, elem.scrollTop 还有,设置它们 Focus elem.focus() 可以触发双强制布局 (source) 另外… elem.computedRole, elem.computedName elem.innerText (source) getComputedStyle window.getComputedStyle() 通常会强制样式重新计算 (source) window.getComputedStyle() 也会强制布局,如果有任何以下是正确的:该元素在阴影树中存在媒体查询(与视口相关的)。具体来说,以下之一:(来源)* min-width、min-height、max-width、max-height、width、height * aspect-ratio、min-aspect-ratio、max-aspect-ratio device-pixel- ratio, resolution,orientation 请求的属性是以下之一:(源)高度、宽度 * 上、右、下、左 * 边距 [-top、-right、-bottom、-left 或简写] 仅当边距是固定的。 * 填充 [-top、-right、-bottom、-left 或简写] 仅当填充固定时。 * 变换、变换原点、透视原点 * 平移、旋转、缩放 * webkit 过滤器、背景过滤器 * 运动路径、运动偏移、运动旋转 * x、y、rx、ry 窗口 window.scrollX、窗口.scrollY window.innerHeight, window.innerWidth window.getMatchedCSSRules() 仅强制样式 Forms inputElem.focus() inputElem.select(), textareaElem.select() (source) 鼠标事件 mouseEvt.layerX, mouseEvt.layerY, mouseEvt.offsetX , mouseEvt.offsetY (source) 文档 doc.scrollingElement 只强制样式 Range range.getClientRects(), range.getBoundingClientRect() SVG 相当多;尚未列出详尽的清单,但 Tony Gentilcore 的 2011 布局触发清单指出了一些。 contenteditable 很多很多东西,...包括将图像复制到剪贴板(来源)
查看更多here。
此外,这里是来自 original issue 的 Chromium 源代码和用于警告的 discussion about a performance API。
编辑:还有一篇关于如何在 PageSpeed Insight by Google 上最小化布局重排的文章。它解释了什么是浏览器重排:
Reflow 是 Web 浏览器进程的名称,用于重新计算文档中元素的位置和几何形状,以重新渲染部分或全部文档。因为重排是浏览器中的一种用户阻塞操作,所以对于开发人员了解如何提高重排时间以及了解各种文档属性(DOM 深度、CSS 规则效率、不同类型的样式更改)对重排的影响很有帮助时间。有时重排文档中的单个元素可能需要重排其父元素以及跟随它的任何元素。
此外,它还解释了如何最小化它:
减少不必要的 DOM 深度。 DOM 树中某一层的更改会导致树的每一层都发生变化——一直到根,一直到被修改节点的子节点。这导致花费更多时间执行回流。最小化 CSS 规则,并删除未使用的 CSS 规则。如果您进行复杂的渲染更改(例如动画),请在流程之外进行。使用 position-absolute 或 position-fixed 来完成此操作。避免不必要的复杂 CSS 选择器 - 特别是后代选择器 - 这需要更多 CPU 能力来进行选择器匹配。
几个想法:
删除一半的代码(可能通过注释掉)。问题还在吗?太好了,您已经缩小了可能性!重复。问题不存在吗?好的,看看你注释掉的那一半!
问题还在吗?太好了,您已经缩小了可能性!重复。
问题不存在吗?好的,看看你注释掉的那一半!
您是否使用任何版本控制系统(例如,Git)?如果是这样,请 git checkout 一些您最近的提交。问题是什么时候引入的?查看提交以确切了解问题首次出现时更改了哪些代码。
git checkout E
来查看问题是否已经存在。如果是,我将继续在提交的前半部分寻找问题。否则,我在下半场寻找问题。
.js
文件并且问题仍然存在......它可能是您通过 <script src="...">
标签引入的库!也许有些事情不值得担心(特别是因为它只是一个警告)?
.js
文件。显然,这很重要。它大大减慢了我的网站。无论如何,再次感谢您的回答和想法。
我在我的代码中找到了这条消息的根,它搜索并隐藏或显示了节点(离线)。这是我的代码:
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');
});
https://i.stack.imgur.com/SbUaa.png
现在:
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'));
});
https://i.stack.imgur.com/XDy3z.png
而且我觉得现在搜索速度更快(229 个节点)。
为了确定问题的根源,运行您的应用程序,并将其记录在 Chrome 的性能选项卡中。
在那里您可以检查需要很长时间才能运行的各种功能。就我而言,与控制台中的警告相关的文件来自 AdBlock 扩展加载的文件,但在您的情况下,这可能是其他内容。
检查这些文件并尝试确定这是某个扩展程序的代码还是您的代码。 (如果是你的,那么你已经找到了问题的根源。)
查看网络选项卡下的 Chrome 控制台,找到加载时间最长的脚本。
就我而言,有一组 Angular add on 脚本,我已包含但尚未在应用程序中使用:
<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 预期的要长——因此发出了警告。
我在 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
});
插入此技巧代码后,所有警告消息都消失了。
在此添加我的见解,因为该线程是有关该主题的“转到”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 />
//...
这是在 Chrome 56 测试版中添加的,即使它不在 Chromium 博客的此更改日志中:Chrome 56 Beta: “Not Secure” warning, Web Bluetooth, and CSS position: sticky
您可以使用隐藏违规复选框将其隐藏在控制台的过滤器栏中。
这是来自 Google Chrome 的违规错误,显示 Verbose
日志记录级别何时启用。
错误信息示例:
https://i.stack.imgur.com/C1Aoj.png
解释:
Reflow 是 Web 浏览器进程的名称,用于重新计算文档中元素的位置和几何形状,以重新渲染部分或全部文档。因为重排是浏览器中的一种用户阻塞操作,所以对于开发人员了解如何提高重排时间以及了解各种文档属性(DOM 深度、CSS 规则效率、不同类型的样式更改)对重排的影响很有帮助时间。有时重排文档中的单个元素可能需要重排其父元素以及跟随它的任何元素。
原创文章:Minimizing browser reflow,用户体验开发人员 Lindsey Simon 发表在 developers.google.com 上。
this is the link Google Chrome 会在性能分析器中的布局配置文件(淡紫色区域)中为您提供有关警告的更多信息。
如果您使用的是 Chrome Canary(或 Beta),只需选中“隐藏违规”选项即可。
https://i.stack.imgur.com/1u1GJ.jpg
当您在执行结束之前多次调用函数时,通常会发生强制回流。
例如,您可能在智能手机上遇到问题,但在经典浏览器上却没有。
我建议使用 setTimeout
来解决问题。
这不是很重要,但我再说一遍,当您多次调用函数时会出现问题,而不是当函数花费超过 50 毫秒时。我认为你的答案是错误的。
关闭 1-by-1 调用并重新加载代码以查看它是否仍然产生错误。如果第二个脚本导致错误,请根据违规的持续时间使用 setTimeOut。
这不是一个错误,只是一个简单的消息。要执行此消息,请将
<!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冗长。
解决办法
console.time
(developer.mozilla.org/en-US/docs/Web/API/Console/time)console.time('UniquetLabelName') ....code here.... console.timeEnd('UniqueLabelName')
而不是使用performance.now()