fre 发布 2.7, diff 算法再优化

216 阅读2分钟

大家好,俺是132,好久不贱,最近考完试闲着没事,把 fre 代码重新梳理了一遍

diff 算法重新梳理+独创优化

fre 的算法可以说是一波三折,因为 fiber 这个结构是在特殊,适配的算法也是一直在换

不像 vue3,copy 一份 inferno 的代码就能拿来用了,哈哈

diff 算法主要分三个级别

  1. 只有 keymap

也就是将旧节点的 key 存起来,可以实现复用旧节点

  1. keymap+首尾预处理

也就是 snabbdom 和 vue2 的算法,在 keymap 的基础上增加了首尾预处理,很大程度上优化了性能

  1. 首尾预处理+lcs/lis

也就是 inferno,vue3 的算法,使用最长公共子序列或最长递增子序列,寻找最大不同,剩下的最小移动

  1. keymap+首位预处理+最大移动距离

也就是在 vue2 算法的基础上,增加距离的判断,进而决定是向前还是向后移动

举例子:

[1, 2, 3, 4, 5]
[1, 3, 4, 5, 2]
[0, -1, -1, -1, 3] // 移动距离

如果是默认 vue2 的算法,这种情况是将 3, 4, 5 都向前移动一个位置,但使用了最长距离的优化后,只需要将 2 向后移动 3 个位置即可

这就是俺找到的优化点,这样一来,就可以做到和 inferno 算法一样的效果,复杂度仍还是 O(n)

请叫我一声天才,啊哈哈

至此,在算法上,已经没有遗憾

  1. 为什么 fre 不适合 lcs/lis?

因为 lis 的复杂度是 O(nlogn),这其实是一个复杂度很高的算法,只不过 vue 那种同步框架中有一个优化,就是先判断 type,type 不同就不进入孩子的遍历,所以很多时候无法命中复杂度高的分支

而 fre 要生成链表,type 判断不同后,也照样得进入 O(n) 的遍历中,进而这个算法得不偿失

所以最好的方法就是仍旧使用 O(n) 的算法,然后在此基础上继续优化

修复 bug

修复了一些和 memo 相关的 bug,感谢 @wooloo 小哥哥

clicli.deno.dev

c站是用fre写的,同样的代码用 preact 就会卡,fre 就不会卡,大家可以本地拉一下试试

我个人是不建议大家使用 fre 的,fre 虽然完成度ok,绝不是玩具,但我个人爱好杂乱,没有太多精力 all in fre,比不得他们团队的

考研

这次终于有学上了,我本来也想在朋友圈发个图乐一乐,但后来想想还是算了,无人在意

但无论如何吧,还是加油,努力,共勉