剖析react核心设计原理--异步执行调度

JS的执行通常在单线程的环境中,遇到比较耗时的代码时,我们首先想到的是将任务分割,让它能够被中断,同时在其他任务到来的时候让出执行权,当其他任务执行后,再从之前中断的部分开始异步执行剩下的计算。所以关键是实现一套异步可中断的方案。那么我们将如何实现一种具备任务分割、异步执行、而且还能让出执行权的解决方案呢。React给出了相应的解决方案。

背景

React起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。该框架主要是一个用于构建用户界面的 JavaScript 库,主要用于构建 UI,对于当时双向数据绑定的前端世界来说,可谓是独树一帜。更独特的是,他在页面刷新中引入了局部刷新的机制。优点有很多,总结后react的主要特性如下:

1. 1 变换

框架认为 UI 只是把数据通过映射关系变换成另一种形式的数据。同样的输入必会有同样的输出。这恰好就是纯函数。

1.2 抽象

​实际场景中只需要用一个函数来实现复杂的 UI。重要的是,你需要把 UI 抽象成多个隐藏内部细节,还可以使用多个函数。通过在一个函数中调用另一个函数来实现复杂的用户界面,这就是抽象。

1.3 组合

为了达到可重用的特性,那么每一次组合,都只为他们创造一个新的容器是的。你还需要“其他抽象的容器再次进行组合。”就是将两个或者多个容器。不同的抽象合并为一个。

React 的核心价值会一直围绕着目标来做更新这件事,将更新和极致的用户体验结合起来,就是 React 团队一直在努力的事情。

变慢==>升级

随着应用越来越复杂,React15 架构中,dom diff 的时间超过 16.6ms,就可能会让页面卡顿。那么是哪些因素导致了react变慢,并且需要重构呢。

React15之前的版本中协调过程是同步的,也叫stack reconciler,又因为js的执行是单线程的,这就导致了在更新比较耗时的任务时,不能及时响应一些高优先级的任务,比如用户在处理耗时任务时输入页面会产生卡顿。页面卡顿的原因大概率由CPU占用过高产生,例如:渲染一个 React 组件时、发出网络请求时、执行函数时,都会占用 CPU,而CPU占用率过高就会产生阻塞的感觉。如何解决这个问题呢?

在我们在日常的开发中,JS的执行通常在单线程的环境中,遇到比较耗时的代码时,我们首先想到的是将任务分割,让它能够被中断,同时在其他任务到来的时候让出执行权,当其他任务执行后,再从之前中断的部分开始异步执行剩下的计算。所以关键是实现一套异步可中断的方案。

那么我们将如何实现一种具备任务分割、异步执行、而且还能让出执行权的解决方案呢。React给出了相应的解决方案。

2.1 任务划分

如何单线程的去执行分割后的任务,尤其是在react15中更新的过程是同步的,我们不能将其任意分割,所以react提供了一套数据结构让他既能够映射真实的dom也能作为分割的单元。这样就引出了我们的Fiber。

Fiber

Fiber是React的最小工作单元,在React中,一切皆为组件。HTML页面上,将多个DOM元素整合在一起可以称为一个组件,HTML标签可以是组件(HostComponent),普通的文本节点也可以是组件(HostText)。每一个组件就对应着一个fiber节点,许多fiber节点互相嵌套、关联,就组成了fiber树(为什么要使用链表结构:因为链表结构就是为了空间换时间,对于插入删除操作性能非常好),正如下面表示的Fiber树和DOM的关系一样:

Fiber树 DOM树

   div#root div#root
      | |
    <App/> div
      | / \
     div p a
    // ↖
  p ----> <Child/>
             |
             a

​一个 DOM 节点一定要着一个光纤节点节点,但一个光纤节点却非常有匹配的 DOM 节点节点。fiber作为工作单元的结构如下:

export type Fiber = {
   
  // 识别 fiber 类型的标签。
  tag: TypeOfWork,

  // child 的唯一标识符。
  key: null | string,

  // 元素的值。类型,用于在协调 child 的过程中保存身份。
  elementType: any,

  // 与该 fiber 相关的已解决的 function / class。
  type: any,

  // 与该 fiber 相关的当前状态。
  stateNode: any,

  // fiber 剩余的字段

  // 处理完这个问题后要返回的 fiber。
  // 这实际上就是 parent。
  // 它在概念上与堆栈帧的返回地址相同。
  return: Fiber | null,

  // 单链表树结构。
  child: Fiber | null,
  sibling: Fiber | null,
  index: number,

  // 最后一次用到连接该节点的引用。
  ref:
    | null
    

你可能感兴趣的:(有道技术团队,react.js,javascript,前端)