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

JavaScript任务长时间运行,耗时234ms 执行JavaScript时强制回流花了45毫秒

我正在做一个小组项目,我不知道这是从哪里来的。这在以前从未发生过。突然,当其他人参与到这个项目中时,它出现了。如何查找导致此警告的文件/函数?我一直在寻找答案,但主要是关于如何解决它的解决方案。如果我连问题的根源都找不到,我就解决不了。

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

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

[违规]Handler占用了231ms的运行时(允许50ms


当前回答

这是谷歌Chrome浏览器的违规错误,显示详细日志级别启用时。

错误信息示例:

解释:

Reflow is the name of the web browser process for re-calculating the positions and geometries of elements in the document, for the purpose of re-rendering part or all of the document. Because reflow is a user-blocking operation in the browser, it is useful for developers to understand how to improve reflow time and also to understand the effects of various document properties (DOM depth, CSS rule efficiency, different types of style changes) on reflow time. Sometimes reflowing a single element in the document may require reflowing its parent elements and also any elements which follow it.

原文:最小化浏览器回流,作者:Lindsey Simon, UX开发人员,发表于developers.google.com。

这是链接谷歌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
});

插入这个恶作剧代码后,所有警告消息都消失了。

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

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毫秒:

Now:

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个节点)。

这里有几个想法:

删除一半的代码(可能通过注释)。 问题还在吗?太好了,你缩小了可能性!重复。 问题不在那里吗?好吧,看看你评论掉的那一半! 你是否使用任何版本控制系统(例如Git)?如果是,git签出一些最近的提交。这个问题是什么时候提出的?查看提交,看看问题第一次出现时到底修改了哪些代码。

在这里添加我的见解,因为这个帖子是关于这个主题的“go to”stackoverflow问题。

我的问题是在一个材质ui应用程序(早期阶段)

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

当我做了一些计算强制渲染页面时 (其中一个组件“显示结果”取决于其他组件“输入部分”中设置的内容)。

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

不管怎样,这是我在遇到

[Violation] Forced reflow while executing JavaScript took <N>ms

警告。所讨论的页面是由用户内容生成的,因此我对DOM的大小实际上没有多大影响。在我的例子中,问题是一个有两列的表,可能有数百甚至数千行。(没有按需行加载实现,对不起!)

使用jQuery,在按下键时,页面选择一组行并切换它们的可见性。我注意到,在该集合上使用toggle()比显式使用hide() & show()更容易触发警告。

有关此特定性能场景的更多详细信息,请参见本文。