Notes Of React
React渲染过程
注:15版本之前
- React.createElement 创建虚拟DOM
- React.render 渲染虚拟DOM
- 通过虚拟DOM创建真实DOM,添加属性、样式、事件等
- 把真实DOM挂载到指定的容器中
react中setState的更新机制(16版本之前)
- 同步更新和异步更新
- 合并更新和不合并更新
- 传入函数不会合并更新
默认:异步合并更新
不在React上下文中,则是同步更新
setState是微任务还是普通任务?
setState本质上是同步执行,state也是同步更新,表现上面是异步的
是否了解过 React 的整体渲染流程? 里面主要有哪些阶段?
爹考答案:
React 整体的渲染流程可以分为两大阶段,分别是render阶段和commit 阶段。
render 阶段里面会经由调度器和协调器处理,此过程是在内存中运行,是异步可中断的。
commit 阶段会由渲染器进行处理,根据副作用进行UI的更新,此过程是同步不可中断的,否则会造成 UI和数据显示不一致。
调度器
调度器的主要工作就是调度任务,让所有的任务有优先级的概念,这样的话紧急的任务可以优先执行。Scheduler 实际上在浏览器的API 中是有原生实现的,这个 API 叫做 requestidleCallback,但是由于兼容性问题,React 放弃了使用这个 API,而是自己实现了一套这样的机制, 并且后期会把 Scheduler 这个包单独的进行发布,变成一个独立的包。这就意味Scheduler 不仅仅是只能在 React中使用,后面如果有其他的项目涉及到了任务调度的需求,都可以使用这个 scheduler。
协调器
协调器是 Render 的第二阶段工作。该阶段会采用深度优先的原则遍历并且创建一个一个的 FiberNode,并将其串联在一起,在遍历时分为了"递”与 归”两个阶段,其中在“递”阶段会执行 beginwork 方法,该方法会根据传入的 FiberNode 创建下一级 FiberNode。而“归”阶段则会执行 CompleteWork 方法,做一些副作用的收集,生成真实DOM。
渲染器
渲染器的工作主要就是将各种副作用 (flags 表示)commit 到宿主环境的UI中。整个阶段可以分为三个子阶段,分别是 BeforeMutation 阶段、Mutation 阶段和 Layout 阶段。
是否了解过 React 的架构?新的Fiber 架构相较于之前的 Stack 架构有什么优势?
参考答案: React v15及其之前的架枸:
- Reconciler(协调器):VDOM 的实现,负责根据自变量变化计算出 UI变化
- Renderer (渲染器):负责将 U 变化渲染到宿主环境中
这种架构称之为 Stack 架构,在 Reconciler 中,mount 的組件会调用mountcomponent,update 的组件会调用updateComponent, 这两个方法都会递归更新子组件,更新流程一旦开始,中途无法中断。
但是随看应用规模的逐渐增大,之前的架构模式无法再满足"快速响应"这一需求,主要受限于如下两个方面:
- CPU瓶颈:由于 VDOM 在进行差异比较时,采用的是递归的方式,JS计算会消耗大最的时间,从而导致动画、还有一些需要实时更新的内容产生视觉上的卡顿。
- IO瓶颈:由于各种基于“自变量”变化而产生約更新任务没有优先級的概念,因此在某些更新任务(例如文本框的输入) 有稍微的延迟,对于用户来讲也是非常敏感的,会让用户产生卡顿的感觉。
新的架构称之为 Fiber 架构:
- scheduler (调度器):调度任务的优先級,高优先級任务会优先进入到 Reconciler
- Reconciler(协调器):VDOM 的实现,负责根据自变量变化计算出UI变化
- Renderer(渲染器):负责将UI变化渲染到宿主环境中
首先引入了 Fiber的概念,通过一个对象来描述一个 DOM 节点,但是和之前方案不同的地方在于,每个Fiber 对象之间通过链表的方式来进行串联。通过 child 来指向子元素,通过 sibling 指向兄弟元素,通过 return 来指向父元素。
在新架构中,Reconciler中的更新流程从递归变为了“可中断的循环过程”。每次循环都会调用 shouldYield 判断当前的 Timeslice 是否有剩余时间,没有剩余时间则暂停更新流程,将主线程还给渲染流水线,等待下一个宏任务再继续执行。这样就解决了 CPU 的瓶颈问题。
另外在新架构中还 入了 Scheduler 调度器,用来调度任务的优先级,从而解决了 I/O 的瓶颈问题。
谈一谈你对 React 中 Fiber 的理解以及什么是Fiber 双缓冲?
参考答案: Fiber 可以从三个方面去理解:
- FiberNode 作为一种架构:在React v15 以及之前的版本中,Reconceiler 采用的是递归的方式,因此被称之为 StackReconciler,到了 React v16 版本之后,引入了 Fiber, Reconceiler 也从 Stack Reconciler 变为了 Fiber Reconceiler, 各个FiberNode 之间通过链表的形式串联了起来。
- FiberNode 作为一种数据类型:Fiber 本质上也是一个对象,是之前虛拟 DOM 对象(React 元素,createElement 的返回值)的一种升级版本,每个Fiber 对象里面会包含 React 元素的类型,周围链接的 FiberNode,DOM 相关信息。
- FiberNode 作为动态的工作单元:在每个 FiberNode 中,保存了“本次更新中该 React 元素变化的数据、要执行的工作(增、删、改、更新Ref、副作用等)"等信息。
所谓 Fiber 双缓冲树,指的是在内存中构建两颗树,并直接在内存中进行替换的技术。在React 中使用 Wip Fiber Tree 和 Current Fiber Tree 这两颗树来实现更新的逻辑。Wip Fiber Tree 在内存中完成更新,而 Current Fiber Tree 是最终要渲染的树,两颗树通过alternate 指针相互指向,这样在下一次渲染的时候,直接复用 Wip Fiber Tree 作为下一次的渲染树,而上一次的渲染树又作为新的Wip Fiber Tree, 这样可以加快 DOM 节点的替换与更新。