site infoHacknerd | Tech Blog
blog cover

🌦️ [React源码解析] 1. 设计理念

JavaScriptReact

异步可中断

React15之前,采用递归更新,更新一旦开始就不可中断。

假设浏览器的屏幕刷新率为60FPS(一帧的时间为16.6ms),如果React一次更新时间超过一帧的时间(js执行会阻塞浏览器绘制)则会造成卡顿。无法响应用户输入,此时就需要一个异步可中断的更新。

  • 1.实现
  • 老React架构

  • 1.分两层 :
  • Reconciler(协调器)—— 负责找出变化的组件
  • Renderer(渲染器)—— 负责将变化的组件渲染到页面上
  • 1.Reconciler(协调器)
  • 当调用this.setState、this.forceUpdate或ReactDOM.remder等其他触发更新的API时,Reconciler(协调器)就会工作。

  • 调用函数组件、或class组件的render方法,将返回的JSX转化为虚拟DOM
  • 将虚拟DOM和上次更新时的虚拟DOM对比
  • 通过对比找出本次更新中变化的虚拟DOM
  • 通知Renderer将变化的虚拟DOM渲染到页面上
  • 1.Renderer(渲染器)
  • React在不同平台有不同的Renderer。

  • ReactDOM渲染器,渲染到浏览器DOM
  • ReactNative渲染器,渲染App原生组件
  • ReactTest渲染器,渲染用于测试的纯JS对象
  • ReactArt渲染器,渲染到Canvas、SVG
  • 4.缺点 在Reconciler中,mount的组件会调用mountComponent,update的组件会调用updateComponent。 这两个方法都会递归更新子组件。 于是形成 call stack 的结构,而递归的过程是不能中断且是同步的,如果当递归层数过深,一旦时间超过16ms,浏览器刷新就会卡顿。

    新的Recat架构

  • 1.分三层 :
  • Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
  • Reconciler(协调器)—— 负责找出变化的组件
  • Renderer(渲染器)—— 负责将变化的组件渲染到页面上
  • 1. Scheduler(调度器) 为了执行程序不超过16.6ms,需要一种机制,让浏览器通知是否有剩余时间,做为要不要中断程序的标准。
  • 2.Fiber Reconciler(协调器)
  • 在React16中,更新从递归变成了可中断的循环。 在每次循环都会调用shouldYield判断当前是否有剩余时间

  • 1.Fiber
  • 在 v16 之前的 React 里,是直接递归遍历 vdom,通过 dom api 增删改 dom 的方式来渲染的。但当 vdom 过大,频繁调用 dom api 会比较耗时,而且递归又不能打断,所以有性能问题。

    后来就引入了 fiber 架构,先把 vdom 树转成 fiber 链表,然后再渲染 fiber。

    在React Fiber架构下,linked list traversal算法在每一个node之间都只会各有一个child(子节点)、sibling(兄弟节点)、return(父节点)。

    image

    代数效应

    获取数据、文件操作等。不同设备性能和网络状况都不一样,react怎样去处理这些副作用,让我们在编码时最佳实践,运行应用时表现一致呢。

    React在获取数据之前会throw一个特殊的Promise,被Scheduler 捕获,暂停更新,等返回数据之后交还执行权。

    Contents

    • 异步可中断
    • 老React架构
    • 新的Recat架构
    • 代数效应

    2024/04/22 02:35