你們好,真的很久不見………………由於如今暑假實習太忙,基本沒太有時間寫本身的東西了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 下的算法~