React 源码学习1-React架构

老的架构-React15的架构

React15使用的架构主要分两层:

  • Reconciler(协调器)
  • Renderer(渲染器)

协调器负责找出组件的变化,也就是我们说的diff,而Renderer负责渲染组件。首先为了方便我们后续更好的理解,先略微讲一下Render工作

JSX

JSX官网
React官网

在这之前我们先将一下JSX,React 使用 JSX 来替代常规的 JavaScript。JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。是FaceBook公司为了方便我们编写代码,研究出的一套特殊语法。JSX的优点有以下几个方面:

  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
  • 它是类型安全的,在编译过程中就能发现错误。
  • 使用 JSX 编写模板更加简单快速。
    我们看以下代码:

代码1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
);
}
}

ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('hello-example')
);

代码2:

1
2
3
4
5
6
7
8
9
10
11
12
class HelloMessage extends React.Component {
render() {
return React.createElement(
"div",
null,
"Hello ",
this.props.name
);
}
}

ReactDOM.render(React.createElement(HelloMessage, { name: "Taylor" }), document.getElementById('hello-example'));

猜测一下这两段代码有什么区别?

其实就是写法上不一样而已,实际的效果是一模一样的。那我们不妨猜测一下JSX的作用?

JSX 会被babel编译成React.createElement方式运行
那到这里,我们继续往下猜测,React.createElement 方法是做什么的?

React.createElement 方法

我们知道,Vue 和React 框架都是基于虚拟dom的。那么React.createDom 方法就是创建虚拟dom节点的方法。那如果存在组件嵌套的情况,在第三个参数那里可以调用React.createElement 去创建一个节点。最后得到一整个虚拟dom节点,交给render函数进行渲染。

ReactDom.render

ReactDom.render 这个函数从名字上来看就可以猜出它是干什么的,就是专门用来把虚拟dom节点转成真实dom节点,最后挂载带页面上。也就是我们说的渲染。那我们可以思考一下,这个dom节点如果很大会怎么样?对就是会卡顿。于是需要在render之前做一下diff。

React 是一个跨平台的框架,所以有多套Renderer。每当Renderer接到Reconciler的通知,Renderer会根据平台来渲染。

Reconciler(协调器)

协调器的作用是 负责找出变化的组件。每当有组件需要更新时,协调器需要做如下工作:

  • 调用函数组件、或class组件的render方法,将返回的JSX转化为虚拟DOM
  • 将虚拟DOM和上次更新时的虚拟DOM对比
  • 通过对比找出本次更新中变化的虚拟DOM
  • 通知Renderer将变化的虚拟DOM渲染到页面上

老架构的缺点

即使有diff算法来优化性能,但如果dom层级很深的话,由于React使用递归的方式来遍历虚拟dom节点,必然会造成视觉上的卡顿。

递归更新的缺点

由于递归执行,所以更新一旦开始,中途就无法中断。当层级很深时,递归更新时间超过了16ms,用户交互就会卡顿。

新的React架构

React16架构可以分为三层:

  • Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
  • Reconciler(协调器)—— 负责找出变化的组件
  • Renderer(渲染器)—— 负责将变化的组件渲染到页面上

    那么什么是调度器?

    Fiber 的三层含义

    • 作为架构来说,之前React15的Reconciler采用递归的方式执行,数据保存在递归调用栈中,所以被称为stack Reconciler。React16的Reconciler基于Fiber节点实现,被称为Fiber Reconciler。
  • 作为静态的数据结构来说,每个Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的DOM节点等信息。

  • 作为动态的工作单元来说,每个Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…)。

    调度器

    我们知道React16最大的更新就是新增了Fiber架构,Fiber架构把一个完整的渲染任务拆成很多个小任务,分成不同的优先级。增量渲染(把渲染任务拆分成块,匀到多帧),十任务渲染更流畅,避免卡顿现象。

调度器处理完任务的优先级,将需要渲染的任务传递给协调器,进行diff。最后传递给renderer进行渲染。