使用React Developer Tools做性能分析

从 React 16.5 开始支持 Chrome 浏览器开发者工具中的 Profiler 性能分析,使用最新的 Profiler 实验性 API 来收集所有 React 组件渲染的耗时,来帮助我们找出 React 应用程序的性能瓶颈。Facebook 官方提供的 Chrome 插件:React Developer Tools,就集成了 Profiler 功能,它可以计算出 React 应用渲染频率及每次渲染耗时,这些都将有助于开发者优化 React 应用性能。

今天我将为大家讲解 React Developer Tools 这个插件。

首先,我们需要先下载 React Developer Tools 插件,只需要在 Chrome 商店中搜索名称后添加即可:

安装好插件后开启,此时需要注意,我们只有在使用了 React 框架开发的网站中才能使用该插件,否则插件无效。

插件成功开启后,打开开发者工具,我们可以看到,插件新增了两个标签页:Components 和 Profiler

接下来,让我们开始了解如何使用它们。这里我为大家准备了一段 React 代码,我们将通过分析它的性能状况来学会使用 React Developer Tools 插件。

javascript 复制代码
import React from 'react';
const ChildOne = (props) => {
    console.log('触发子组件ChildOne的render')
    return (
        <div className="box">
            <p>子组件ChildOne</p>
            <div>父组件传入props数据{props.value}</div>
        </div>
    )
};
const ChildTwo = () => {
    console.log('触发子组件ChildTwo的render')
    return (
        <div className="box">
            <p>子组件ChildTwo</p>
        </div>
    )
}
const ChildThree = React.memo(() => {
    console.log('触发子组件ChildThree的render')
    return (
        <div className="box">
            <p>子组件ChildTwo</p>
        </div>
    )
})
class App extends React.Component {
    state = {
        value: 1,
    };
    handleClick = () => {
        const {value} = this.state
        this.setState({
            value: value + 1,
        });
    };
    render() {
        console.log('触发render')
        return (
            <React.Fragment>
                <div className="box">
                    <div>我是父组件</div>
                    <button onClick={this.handleClick}>+</button>
                </div>
                <ChildOne value={this.state.value}/>
                <ChildTwo/>
                <ChildThree/>
            </React.Fragment>
        );
    }
}
export default App;

启动项目后查看开发者工具,点击 Components 标签页,可以查看组成应用的 React 组件树。

左侧区域显示了完整的 React DOM 结构:App 父组件下有 div、ChildOne、ChildTwo、ChildThree 三个子组件,其中 ChildThree 还是使用 Memo 封装后的高阶组件;右侧区域可查看对应组件的 props、state 及组件渲染过程的堆栈信息。

当 React 组件过多时,我们可以很方便的通过组件名进行搜索:

也许你会问,这里的 React DOM 跟 Elements 标签页下的有什么区别呢?首先,Components 标签页中展示的是 react 组件,对于 React 开发者来说,可以很直观的查看 React 组件的名称,state 和 props 等信息,在调试时会更方便。此外,当我们使用 React Portals 的时候,也会为你带来很大的便利性。

javascript 复制代码
import React from 'react';
import ReactDOM from 'react-dom';
const appRoot = document.getElementById('root');
const modalRoot = document.getElementById('modal-root');
class Modal extends React.Component {
    constructor(props) {
        super(props);
        this.el = document.createElement('div');
    }
    componentDidMount() {
        modalRoot.appendChild(this.el);
    }
    componentWillUnmount() {
        modalRoot.removeChild(this.el);
    }
    render() {
        return ReactDOM.createPortal(
            this.props.children,
            this.el,
        );
    }
}
class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {showModal: false};
        this.handleShow = this.handleShow.bind(this);
        this.handleHide = this.handleHide.bind(this);
    }
    handleShow() {
        this.setState({showModal: true});
    }
    handleHide() {
        this.setState({showModal: false});
    }
    render() {
        const modal = this.state.showModal ? (
            <Modal>
                <div className="modal">
                    <div>
                        With a portal, we can render content into a different
                        part of the DOM, as if it were any other React child.
                    </div>
                    This is being rendered inside the #modal-container div.
                    <button onClick={this.handleHide}>Hide modal</button>
                </div>
            </Modal>
        ) : null;
        return (
            <div className="app">
                This div has overflow: hidden.
                <button onClick={this.handleShow}>Show modal</button>
                {modal}
            </div>
        );
    }
}
ReactDOM.render(<App />, appRoot);

我们在 Components 标签页下可以看到 button 与 Modal 组件是兄弟节点,但在真实的 DOM 中也是这样吗?点击右侧的查看按钮:

会发现跳到了 Elements 标签页下,而真实的 DOM 结构却是 button 和 Modal 根本不在同一个父节点中!

插件的这种展现形式更有利于我们在进行 React 开发中定位问题。

如果你对 React 的基本原理有一定了解,应该知道,React 的运行分为两个阶段,

第一阶段是组件渲染阶段,在这个阶段,React 将会确定诸如 DOM 之类的数据需要做那些变化,之后开始执行各个组件的 render 方法,最后。

第一阶段结束后进入第二阶段,组件 commit 阶段,React 会提交所有变更,所谓变更指的是 React 添加、修改和移除 DOM 节点等行为,并且在这个阶段,React 会执行像 componentDidMount 和 componentDidUpdate 这类周期函数。

我们今天所说的 Profiler 正是在第二阶段,也就是组件 commit 阶段的时候收集性能数据。

使用 Profiler 前,首先让我们进行一些简单的设置。点击设置按钮,可看到四个配置项:

General 中的基本设置可配置显示主题及展示的紧凑类型,勾选中第三行可选框后,每次组件有重新渲染时就会显示出蓝色边框,我们在开发的时候能够更直观的了解到渲染状态。

Debugging 可配置在使用 Profiler 时如遇到报错是否展示与暂停

Components 可配置查看报告时的过滤标签,通常我们只希望看自定义业务组件,因此需要过滤掉无用的容器组件,例如 div

Profiler 可配置是否展示引起 render 的来源及根据时间过滤 commit

设置完成后让我们回到 Profiler,可看到一共有三个子标签,对应 Profiler 的三大功能:

我们以第一个案例代码做演示,点击开始按钮后,连续点击页面中的 + 号 3 次,再点击结束按钮,此时可看到 Profiler 标签页已经显示出内容:

上方的柱状图与 3 次操作相对应,可通过左右按钮进行切换查看,柱状图的高低标识当次渲染时间的长短:

右侧区域显示了当次 commit 的基本信息,一共有 4 个信息提供给开发者,包括 Priority:是否是立即执行,是否被其他高优操作打断;Commit at:commit 发生的时间点;Render duration:渲染时长;Interactions:是否有交互行为

接下来,让我们看看右侧区域,

Flamegraph 子标签下的火焰图,展示了当次 commit 各个组件的渲染时间,可点击其中的柱状条,会展示出组件的具体渲染信息。

对 ChildOne 组件,由于父组件传入的 props 的 value 变化触发了 render,三次操作它的 render 时长为 1.1ms、1.1ms 和 1.3ms。

对 ChildTwo 组件,则是由于父组件的重新渲染触发了其渲染,但并没有 props 和 state 的变化,大家一定要记住,这种可以被认为是无意义的渲染,因此是我们可以优化的一个点!

对 ChildThree 组件,图中可看出它与 ChildOne 和 ChildTwo 的颜色并不相同,是的,Profiler 插件用白色底标识该组件在当次 commit 中并未触发 render!

点击 Ranked 子标签,列出了当次 commit 中,各个组件的渲染时长从高到低的排序,可直观看到每个组件的渲染情况,方便开发者找出渲染性能最差的组件,可以有针对性的执行优化:

interactions 子标签是用于跟踪更新原因的实验性 API。被这些 API 跟踪的"交互动作"也会显示在 profiler 中,它的使用需结合 trace api:

javascript 复制代码
import { unstable_trace as trace } from "scheduler/tracing";
handleClick = () => {
    const {value} = this.state
    trace("click btn", performance.now(), () => {
        this.setState({
            value: value + 1,
        });
    });
};

点击后的显示每次点击发生的时间点和持续的时间,对查看交互行为的性能尤为有用。

最后,我们来总结一下今天的内容:React Developer Tools 插件的使用主要分为两大部分:Components 和 Profiler。

Components 标签中提供了查看 React 中所有组件树形结构的功能,这对查找使用了 React Portals 的组件不再有结构不一致的困扰。除此之外 Components 还提供了查看单个组件 props 和 state 的功能;

Profiler 标签为我们提供了 React 组件的各项性能数据,包括查看每次 commit 的基本信息,各组件渲染时长排名,发生交互时的交互信息,交互时间、交互时间点等。还可以很方便的查看各组件渲染的火焰图。

相关推荐
旺旺大力包2 分钟前
【 React 】重点知识总结 && 快速上手指南
开发语言·前端·react.js
咪库咪库咪7 分钟前
使用Fetch api发起请求
前端
东华帝君9 分钟前
nuxt + nuxt ui + nuxt i18n
前端
jingling55513 分钟前
前端开发核心知识详解:Vue2、JavaScript 与 CSS
javascript·css·vue.js
AronTing18 分钟前
单例模式:确保唯一实例的设计模式
java·javascript·后端
鹿九巫22 分钟前
【CSS】超详细!一篇文章带你学会CSS的层叠,优先级与继承
前端
天天码行空44 分钟前
UnoCSS原子CSS引擎-前端CSS救星
前端
1_2_3_1 小时前
抛弃 if-else,让 JavaScript 代码更高效
前端
火星思想1 小时前
再来看看「从输入 URL 到看到页面」的整个流程
前端·面试
张开心_kx1 小时前
不要再代码中滥用 useCallback 和useMemo
前端·react.js