你们好,真的很久不见………………由于如今暑假实习太忙,基本没太有时间写本身的东西了react
悲剧……因此一直想要重构 fre,拖到如今才实现,下面看看此次更新主要作了什么事情:git
在以前的版本中,时间切片主要是借助 requestIdleCallback 完成的,它存在一些问题,好比兼容性不好(主要是小程序不支持),好比不可控(没法控制切片的帧率,丢帧也不知道),总之这个 API 确定要搞掉的github
react 的时间切片,是基于 requestAnimation + 优先级 来调度实现的,理想状态下,fre 也应该这么作算法
const FPS = 1000 / 60
function workLoop (startTime = 0) {
if (startTime && performance.now() - startTime > FPS) {
requestAnimationFrame(workLoop)
} else {
const nextTime = performance.now()
nextWork = performWork(nextWork)
if (nextWork) {
workLoop(nextTime)
} else {
options.commitWork
? options.commitWork(pendingCommit)
: commitWork(pendingCommit)
}
}
}
复制代码
如上图,fre 一样基于 requestAnimationFrame 实现了一个超级小的调度,它的原理是这样的:小程序
如上,短短的十行代码,切片的同时,拥有较好的兼容性,并且切片的过程还可控,之后随时能够将更新队列按照优先级进行排序缓存
如今的 fre 能够说是孤立无援,react 的 diff 看不懂,其余框架的 diff 不适用于 fiber框架
本次优化主要是针对两个 case:异步
function App () {
const [arr, setArr] = useState(['A', 'B','C','D'])
return (
<div> <ul> {arr.map(item => ( <A key={item} val={item}/> ))} </ul> <button onClick={() => setArr(['B','A','D','C'])}>+</button> </div> ) } function A(props){ return <div>{props.val}</div> } 复制代码
如上,这个是其中一个 case ,将 key 加到组件上,此时的 key 应该转移到组件内部的函数
根元素(div)上,这也是为何咱们要求组件必须有一个元素包裹的缘由oop
若是不这么作,key 加到组件上,等于没加
{
isShow && <A /> isShow ? <A /> : null isShow ? <A /> : <B /> } 复制代码
这是另外一个 case,以前一直想优化这种状况,发现很是困难,后来发现我是错的
这种 case 是很难优化的,因此移除掉这部分的优化,尺寸也有史以来的第一次缩减到 1.7kb
位置的变化是很困难的,只有加 key 的状况能够作到位置变化
终于搞懂了 useMemo / useCallback / useEffect 的关系,以前的实现有点点问题,新版本处理掉了
useMemo 是根据第二个参数判断是否须要从新计算并返回一个缓存过的 值
useCallback是根据第二个参数判断是否须要从新生成并返回一个缓存过的 函数引用
useEffect 是根据第二个参数判断是否须要执行这个函数
总结 综上所述,fre 新版本逻辑更加精巧了,我也按照约定,搞了时间切片和调度,至此,fre 算得上麻雀虽小,五脏俱全了
github 地址:github.com/132yse/fre
孤立无援,欢迎老铁加入进来,一块儿研究 fiber 下的算法~