从渲染原理到性能优化

@kvkens 2018-12-10 07:13:04发表于 iuap-design/blog

从渲染原理到性能优化

通过最近的台湾项目,当功能做成后,性能成了瓶颈,就拿行编辑来说,不了解这些下面知识点,是无法做优化的,大致分为4个章节去阐述问题

一、JSX如何生成element

二、element如何生成真实DOM节点

三、性能优化

四、React 16异步渲染方案

1. JSX如何生成element

jsx:

return(
  <div className="cn">
  <Header> Hello, This is React </Header>
  <div>Start to learn right now!</div>
Right Reserve.
  </div>
)

经过babel->
js:

return (
    React.createElement(
        'div',
        { className: 'cn' },
        React.createElement(
            Header,
            null,
            'Hello, This is React'
        ),
        React.createElement(
            'div',
            null,
            'Start to learn right now!'
        ),
        'Right Reserve'
    ))

createElement的作用是生成element,
参数如下
1、type
2、attributes,如果没有的话,可以为null
3、children

React.createElement 何时被执行?

Render 函数被调用的时候执行

JSX

React.createElement(
  'div',
  { className: 'cn' },
  React.createElement(
    Header,
    null,
    'Hello, This is React'
  ),
  React.createElement(
    'div',
     null,
     ‘Start to learn right   now!'
  ),
  'Right Reserve'
)
{
  type: 'div',
  props: {
    className: 'cn',
    children: [
      {
        type: function Header,
        props: {
          children: 'Hello, This is React'
        }
      },
      {
        type: 'div',
        props: {
          children: 'start to learn right now!'
        }
      },
      'Right Reserve'
    ]
  }
}

Element

{
  type: 'div',
  props: {
    className: 'cn',
    children: [
      {
        type: function Header,
        props: {
          children: 'Hello, This is React'
        }
      },
      {
        type: 'div',
        props: {
          children: 'start to learn right now!'
       }
      },
      'Right Reserve'
    ]
  }
}

Children现在看到有三种类型:

1.String,

2.原生DOM节点的element

3.React components – 自定义组件的element

不单单是Object类型

4.false, null,undefined,number

5.数组 – 使用map方法的时候

二、element如何生成realDOM

我们知道React是函数式的UI编程方式,element实际就是描述你想要在屏幕上看到什么。所以我们来看看React是怎么帮助我们把它生成浏览器的真实DOM节点。

初始化element

image

  • 私有类: React自己使用,不会暴露给用户,常用方法:mountComponent, updateComponent等
  • 公共类:自定义的组件

ReactDOMComponent

mountComponent(container): 会将element转成真实DOM节点,并且插入到相应的container里,然后返回markup(real DOM)。

{
    type: 'div',
        props: {
        className: 'cn',
            children: 'Hello world',
    }
}
mountComponent(container) {
    const domElement = document.createElement(this._currentElement.type);
    const textNode = document.createTextNode(this._currentElement.props.children);
    domElement.appendChild(textNode);
    container.appendChild(domElement);
    return domElement;
    }
  

ReactCompositeComponentWrapper

mountComponent: 实例化自定义组件,最后是通过递归调用到ReactDOMComponent的mountComponent方法
来得到真实DOM。

首次渲染

image

ReactCompositeComponentWrapper

React.render<Example />, container)

转换为:

{
   type: function Example,
   props: {
     children: null
   }
}
<div>Hello World!</div>
{
  type: 'div',
  props: {
     children: 'Hello World'
  }
}

mountComponent:
1.实例化Example,得到instance对象;

2.renderedElement = Instance.render();

3.初始化renderedElement ,得到child

4.child.mountComponent(container)

ReactDOMComponent

mountComponent:
根据element来生成对应的真实DOM节点

image

image

渲染更新

image

image

image

Diff算法

1.两个相同的组件产生类似的DOM结构,不同组件产生不同DOM结构

image

2.对于同一层级的一组子节点,它们可以通过唯一的id区分

3.不同节点类型
image

4.相同节点类型

<div className="before" title="stuff"/>
<div className="after" title="stuff"/>
  1. 子节点比较

image

三、性能优化

性能优化 -工具介绍

  1. why-did-you-update

image

  1. react-addons-perf

image

1. Mount/Unmount

  • Key
  • 稳定性
    • 保持标签的稳定 <div> -> <section>
    • 保持DOM结构的稳定

2. 避免重复渲染

  • shouldComponentUpdate
  • PureComponent(immutable.js)
  • 分离组件,只传入关心的值

3. 使用Pure Functional Component

目前react 性能优化的点主要集中在防止重复渲染,DOM稳定性的方面:

四、React 16异步渲染方案

1、比较阶段 – 可被打断

2、commit阶段 – 不可被打断

image

React 16生命周期的变化

image

拓展阅读

1、function component

九个推荐使用functional component的原因

七个不使用functional component的 原因

2、getDerivedFromProps

如何异步渲染开启后,我们要做的改变

你可能不需要使用getDerivedState

3、presentational/container components