snabbdom是非常经典的一个库了。
曾经在知乎上看到有这样一个问题,发现virtual-dom也是不少人都造过的轮子。
snabbdom的牛逼之处更多在于思想,而不是在于代码有多么的精妙,这一点在react和vue都用virtual-dom的思想去做dom的处理而又对其做了优化这件事情中可见一斑。
前言
- 实际上在刚看到源码的时候也是有些一脸懵逼,所以就从第一个commit开始看了,确实不失为一个好方法,虽然可能花的时间会稍微长一点0.0,好处在于可以了解到作者最初的想法。
- diff的部分实际上已经有非常非常多讲的很通俗的文章,写的辣鸡的地方可以评论补(peng)充(wo)啦,感谢!
项目结构
先来看下项目结构
modules文件夹里面都是拆分出来的简单替换和对比的一些函数,都比较简单可以自行查看。
hero文件里面放了snabbdom的钩子函数,也就是hook,会在snabbom的init函数调用的时候收集,在对应的时候执行,同时里面通过requestAnimationFrame做了一些动画上的优化。
其他比较核心的有
-
h函数(传入对应参数生成vnode)
-
html(domapis一些dom-api封装)
-
snabbdoms.bundle(打包的一些处理)
-
snabbdom(主文件核心逻辑都在这里,主要分析这个里面的代码)
-
thunk(对patch的一些优化)
-
vnode(定义了virtual-dom的结构)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16export interface VNodeData {
props?: Props;
attrs?: Attrs;
class?: Classes;
style?: VNodeStyle;
dataset?: Dataset;
on?: On;
hero?: Hero;
attachData?: AttachData;
hook?: Hooks;
key?: Key;
ns?: string; // for SVGs
fn?: () => VNode; // for thunks
args?: Array<any>; // for thunks
[key: string]: any; // for any other 3rd party module
}
vnode的结构可以从定义的接口看出
分析
这段代码也就是我们常说的diff,也就是updateChildren的这个函数,接受了两个children数组来进行对比
1 | function updateChildren(parentElm: Node, |
以上把代码都做了一个注释,有兴趣的话可以拿张纸笔画画图会比较清晰(自己也是这么做的)。
一些疑惑和疏漏
- 在查看比较前面的commit发现在最开始有用到createDocumentFragment这个api来避免浏览器多次渲染导致的回流和重绘,但发现后面给移除了…不太明白0.0
- hook这个地方实际上有个很小的疑惑,在init的时候可以发现他的hook数组里面一般只有一个回调需要执行,为什么以数组的形式保存,可能是后面还有没写的hook?
- patch的部分也可以细讲(懒了)
- hook的几个函数没讲出来,之后再回头看看吧(咕咕咕)
水文结束
优化的细节实际上很多,阅读优秀的开源项目能收获到不少平时写代码的技巧。
第一个commit十分简单,可以慢慢翻到补充稍微完整的源码之后再跳着看,这样可能会比较快。
最近翻了翻pr,发现作者已经很久没有合并pr或者更新代码了,ci的test好像也有问题…
原来是有了新欢turbine,好像也蛮有意思的,就是相关资料有点少,之后有空的话去看看啦~
Comments