【问题标题】:React Performance Issues in Firefox?Firefox 中的 React 性能问题?
【发布时间】:2020-05-19 07:55:58
【问题描述】:

我在使用我开发的 React 应用程序时遇到了一些性能问题。这些问题在 Firefox(FF developer 77.0b7 和 FF 76.0.1)中特别(或最显着)出现。

在 Firefox 中使用此应用程序时,CPU 使用率变得非常高,我的粉丝开始以非常高的速度旋转。根据FF中的性能工具,我在firefox中得到大约15-19fps。我在 Chrome 和 Safari 中获得大约 60fps。

当我开始在输入字段中输入内容时会出现这些问题,并且随着输入时间变长(这是有道理的)变得更糟

该应用程序可在此处获得: https://text-to-aura-generator.netlify.app/

此处提供源代码:https://github.com/paalwilliams/Text-to-Aura/tree/master/src

我几乎可以肯定这是我做错了,或者我编写的代码效率低下,但这并不一定受到浏览器之间明显的性能差异的支持。 chrome 在处理反应/常量重新渲染方面是否更好?

我知道这是一个广泛的问题,但老实说,我不明白这里发生了什么,或者必然如何在开发人员工具之外对其进行故障排除。任何意见或想法将不胜感激。

【问题讨论】:

    标签: javascript reactjs firefox


    【解决方案1】:

    问题是您的应用程序渲染速度过快。在您的特定情况下,有几种方法可以改善这一点。

    每次更新状态时,React 都需要重新渲染应用程序,因此在循环中更新状态通常是个坏主意。

    另外,您使用了useState 3 次,但应该只有colors,因为App 实际上需要重新渲染以反映那里的变化。另外两个状态(text 和hex)仅用于将数据从handleChange 传递到useEffect 内部的回调。

    您可以将代码重构为:

    • 避免在循环中更新状态。

    • 使用简单的变量代替状态。

    • 使用useCallback 定义一个函数,该函数不会在每次渲染时重新创建,因为这会强制TextInput 也重新渲染。

    • 使用类似这样的方式限制此回调:

      import { useCallback, useEffect, useRef } from 'react';
      
      export function useThrottledCallback<A extends any[]>(
        callback: (...args: A) => void,
        delay: number,
        deps?: readonly any[],
      ): (...args: A) => void {
        const timeoutRef = useRef<number>();
        const callbackRef = useRef(callback);
        const lastCalledRef = useRef(0);
      
        // Remember the latest callback:
        //
        // Without this, if you change the callback, when setTimeout kicks in, it
        // will still call your old callback.
        //
        // If you add `callback` to useCallback's deps, it will also update, but it
        // might be called twice if the timeout had already been set.
      
        useEffect(() => {
          callbackRef.current = callback;
        }, [callback]);
      
        // Clear timeout if the components is unmounted or the delay changes:
        useEffect(() => window.clearTimeout(timeoutRef.current), [delay]);
      
        return useCallback((...args: A) => {
          // Clear previous timer:
          window.clearTimeout(timeoutRef.current);
      
          function invoke() {
            callbackRef.current(...args);
            lastCalledRef.current = Date.now();
          }
      
          // Calculate elapsed time:
          const elapsed = Date.now() - lastCalledRef.current;
      
          if (elapsed >= delay) {
            // If already waited enough, call callback:
            invoke();
          } else {
            // Otherwise, we need to wait a bit more:
            timeoutRef.current = window.setTimeout(invoke, delay - elapsed);
          }
        }, deps);
      }
      

    如果使用useEffect 的原因是您在更新colors 时没有看到正确的值,请尝试使用接受回调而不是新值的setState 版本,所以不要:

    setColors([...colors, newColor]);
    

    你会:

    setColors(prevColors => ([...prevColors , newColor]));
    

    【讨论】:

    • 谢谢!我会继续并包含这些更改并返回:)
    • 不过,我还是很好奇,为什么 firefox 和 chrome 之间的性能差异如此明显。 chrome 在编译和运行 js 密集型应用程序方面真的要好得多吗?值得注意的是,我在其他应用程序中也注意到了这种性能差异。我正在使用新的 facebook 测试版,它都是响应式的,它在 Firefox 中滞后且通常速度较慢,但​​在 Chrome 中明显更好。
    • @Paal 由于他们使用不同的引擎,因此性能也会有所不同,并且可能在某些领域中一个比另一个更好,而在其他一些领域则相反。话虽如此,由于您的代码存在问题,使用功能较弱的计算机在 Chrome 上运行速度也会很慢。实际上,您可以使用 DevTools 来限制 CPU 并查看您的应用在速度较慢的设备上的表现。在足够强大的硬件上,您几乎总是可以运行缓慢的代码而不会出现明显问题。
    【解决方案2】:

    React 最常见的性能问题来自于设置状态的次数过多,因为您不断地重新渲染页面和其中的元素。

    【讨论】:

    • 我觉得在输入更改上设置状态是相当合理的状态更改量,不是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    相关资源
    最近更新 更多