limbos
v2.2.0
Published
a mini-react force on / concurrent mode / event-system / fiber
Readme
limbo
a mini-react force on / concurrent mode / event-system / fiber
why limbo
- 支持自适应帧率的
schedule系统 - 比react性能更好的高效渲染与更新
- 完整的中断与恢复系统
suspense - 支持模板与
JSX渲染 - 体积极小
limbo lis diff
limbo引入了算法优化diff过程,在极端情况下与vue3的children reconcile性能一致。
需要注意的是,
react同样引入了简化(or改进)的算法优化diff过程,在某些场景下可能会节省lis算法的内部处理时间。
suspense
limbo内置了suspense,这意味着limbo也拥有了完整的中断/恢复功能。
调度策略
limbo支持最大120帧,并且能自动启发式的更新调度时长,保证应用流畅。
下面简单介绍一下limbo的调度策略
拆分:
limbo把任务拆成了两种level:
- re-render
- single fiber
并对每种级别任务的最小运行周期时做了shouldYield检查,并在下一个帧工作时间恢复未完成的任务。
一个简单的调度
function beginWork(work) {
requestIdleCallback(deadline => {
while(deadline.timeRemaining) {
work.next()
}
if(!work.done) beginWork()
})
}
function *reconcile(hostFiber){
currentTask = asyncDiffHookFiber(hostFiber.children)
while(childTraversed) {
while(!shouldYield() && !currentTask.done()) yield currentTask.next()
}
}
function *asyncDiffHookFiber(fiber) {
// 我们假设它无递归Hook子节点
while(childTraversed) {
yield* syncDiffHostFiber(fiber.children)
}
}use
hooks
limbo不支持class component,但全面支持hooks:
- useState
- useReducer
- useRef
- useEffect
- useLayoutEffect
- useCallback
- useMemo
- useContext
你可以效仿react的方法写limbo
useState
import { useState, h } from 'limbo'
function App() {
const [state,setState] = useState(0)
return <button>current:{state}</button>
}useEffect
import { useEffect, h } from 'limbo'
function App() {
useEffect(() => {
...
return () => {}
})
return <button>current:{state}</button>
}组件
limbo提供了几个重要的组件:
- Context
- Keep-Alive
- Fragment
Keep-Alive
Keep-Alive组件类似Vue的Keep-Alive组件,它支持在组件卸载后依然保留vnode。并在恢复时保证状态不丢失。
Context
Context是标准的上下文缓存组件,具体功能参考React。
Fragment
Fragment是一个包装组件,它不会被实际渲染。
eg: 以下三个组件都会被渲染
<Fragment>
<Parent1 />
<Parent2 />
<Parent3 />
</Fragment>template
limbo拥有一套完善的模板渲染引擎。引擎将会在内部对模板内容进行优化,在可能出现大量变更的场景下,模板拥有比JSX更高效的更新。
编译模板
jsx与template是两个不同的写法,并不能互相兼容。
使用template,需要在template外层的函数前一行添加注释//@template
一个例子如下:
//@template
const Comp = () => {
const [data] = useState([1,2,3])
return <div l-for="v in data">{v}</div>
}当template无法编译(出现语法错误)时,会自动退化为JSX。
需要注意的是,不要在template里使用注释。
模板指令
l-ifl-elifl-elsel-bindl-for
循环
模板支持循环功能,例子如下:
<div l-for="(data, index) in array">{data}</div>上面的模板会被编译为:
array.map((data, index) => <div>{data}</div>)条件
模板支持条件功能,通过l-if, l-elif, l-else来指定对应的条件分支。
一个简单的demo如下:
<div l-if="isRender">if</div>
<div l-elif="isRender2">elif</div>
<div l-else>else</div>需要注意的是,上面代码里的l-if对应的isRender不是字符串,而是Javascript变量isRender。
注意: 条件指令里不能将字符作为条件变量,所有条件变量都被编译为Javascript变量。
