1.时间切片
主流浏览器刷新频率为60hz,即约16.7ms刷新一次(一帧);所以相当于16.7ms要做完js执行,浏览器布局绘制,react会在每一帧预留一定的时间用于浏览器绘制渲染,js没执行完会放在下一帧去执行
每一帧js执行时间大概在5ms,这种把同步更新转化为可中断的异步更新的能力叫时间切片
2.react的三层架构
- Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
- Reconciler(协调器)—— 负责找出变化的组件
- Renderer(渲染器)—— 负责将变化的组件渲染到页面上
scheduler会识别任务优先级,将高优任务交给reconciler,协调器会为有改动的dom节点打上改变类型的印记(增删改),当所有的组件执行完reconciler的工作后,进入renderer流程。
以上内容都在内存中执行,不会更新页面dom,所以即使反复中断,用户也不会看见更新不完全的dom
renderer根据标记同步执行对应的dom操作。
3.fiber的三层架构
每一个fiber对应了一个react节点,能够保存dom节点信息,更新状态,***父级,子级,下一个兄弟(sibling),优先级(lane)***等等
在react中会存在两棵树,当前页面展示的current fiber树和正在绘制的workInProgress Fiber树,每次更新将workInProgress Fiber切换为新的current fiber。
4.jsx
jsx实际上就是React.createElement(type,config,children)的语法糖 jsx只描述结构,并没有fiber上述斜体属性
从react17开始,上述说法就不对了。无需在文件自行引入React。
5.render流程
采用递归方式,深度优先遍历整棵fiber树,执行beginWork;判断每一帧是否有空闲时间,如有就由下至上执行CompleteWork,没有则中断,直到在内存中画出整棵新的fiber树,之后去替换current Fiber。
benginWork的工作内容分为mount和update:mount意味着是第一次render,current === null,所以去生成新的节点;如果是更新则执行update,diff算法就应用在此过程。详情可见diff
CompleteWork根据不同的节点类型执行不同操作(FunctionCompoent,ClassComponent,Text,HostComponent等等),同样分为mount和update:update意味着此时dom上已经有实际存在的节点,所以不需要生成新的dom,只需处理style,props,各种事件的注册等等;mount则需要生成新的dom子节点并将其插入到父节点中。
complete执行完后,会按照顺序生成一个单向链表effectList,供后续commit使用
6.commit流程
renderer的执行是在commit阶段而非render阶段,render只是用来生成fiber树
主要工作: useEffect等相关hook的执行,以及性能相关追踪
可分为三个阶段:
before mutation 执行dom操作前
异步执行useEffect
mutation 执行dom操作
根据effectTag调用不同的处理函数处理Fiber
layout 执行dom操作后
根据effectTag调用不同的处理函数处理Fiber并更新ref
7.diff算法
一个dom节点最多会与4个节点相关,diff算法的本质就是将jsx对象与currentFiber做对比,然后生成workInProgressFiber,最后渲染为dom节点
diff的限制: 只对同级元素做diff,标签属性变更后会销毁该dom以及子节点并重新创建,可以通过key指明可复用节点。
diff的复用需要key和type相同。
多节点diff算法: 单向遍历,优先执行更新操作,
遍历新节点,如果与旧节点的key和type相同则复用;key相同type不同则删除旧节点继续遍历;key不同则跳出循环无法遍历。
例子: 原节点: abcd
新节点: dabc
操作: 保持d节点不变,将abc向后移动
8.各种hook
useState
多个useState会形成一个单向环形链表,
query.pending始终指向链表的最后一个,即query.pending.next始终指向链表的第一位
因此,hook不能放在条件判断或for循环中去执行,必须保证hook在每次渲染中按同样的顺序去调用
useEffect
首先执行所有useEffect的销毁函数,再执行回调。
useRef
render阶段为含有ref属性的fiber添加Ref effectTagcommit阶段为包含Ref effectTag的fiber执行对应操作
useMemo&useCallback
9.lane模型
使用31位的二进制表示31条赛道,位数越小的赛道优先级越高,某些相邻的赛道拥有相同优先级。
例: 0X000001 高优先级
0X000110 中优先级
0X111000 低优先级
之后按位与,获取当前需执行的高优先级任务