当我们用canvas绘制动画,每一帧绘制前都会调用ctx.clearRect清除上一帧的画面。
如果当前帧画面计算量比较大,导致清除上一帧画面到绘制当前帧画面之间有较长间隙,就会出现白屏。
为了解决这个问题,我们可以在内存中绘制当前帧动画,绘制完毕后直接用当前帧替换上一帧画面,由于省去了两帧替换间的计算时间,不会出现从白屏到出现画面的闪烁情况。
这种在内存中构建并直接替换的技术叫做双缓存(opens new window)。
React使用“双缓存”来完成Fiber树的构建与替换——对应着DOM树的创建与更新。
双缓存Fiber树
React中最多会同时存在两棵Fiber树,当前屏幕显示的Fiber树(current Fiber树),正在内存构建的Fiber树(workInProgress Fiber树)
current Fiber的Fiber节点被称为current fiber,workInProgress的Fiber节点被称为workInProgress Fiber,通过alternate属性连接。
currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;
React应用的根节点(FiberRootNode)通过current指针在不同的Fiber树的rootFiber间切换来完成current Fiber树指向的切换。<br />当workInProgress Fiber树构建完成交给Renrer渲染页面上后,应用根节点的current指向workInProgress Fiber树,此时workInProgress Fiber变成current Fiber树。<br />每次状态更新都会产生新的workInProgress Fiber树,通过current与workInProgress的替换,完成DOM更新。<br />
1、mount时
1、首屏渲染
页面没有挂载任何Dom,只有fiberRootNode.current指向RootFiber,没有任何子fiber节点。
2、Render阶段
根绝组件返回的jsx在内存中依次创建fiber节点,并连接形成fiber树(workInProgress Fiber树)
(右侧是内存构建的树,左侧时界面显示的树)
在构建workInProgress Fiber树时会尝试复用current Fiber树中已有的Fiber节点内的属性。
3、workInprogress Fiber树在commit 阶段渲染到页面
fiberRootNode的current指针指向workInProgress Fiber树,使其变成current Fiber树。
2、update时
1、点击p节点促发状态改变,开启一次新的render阶段,构建一颗新的workInProgress Fiber树。
和mount时一样,workInProgress fiber的创建可以复用current Fiber树对应的节点数据(过程就是diff算法)。
(无论是首屏渲染、setState、this.state都会创建一个rootFiber,通过alternate连接共用一些属性,通过深度遍历形成一个Fiber树)
2、workInProgress Fiber树在render阶段完成构建后进入commit渲染到页面上
fiberRootNode的current指针指向workInProgress Fiber树,使其变成current Fiber树。