snabbdom源码粗读
snabbdom
本文的snabbdom源码分析采用的是0.54版本(即未用ts重写前的最后一版)
前期了解
snabbdom被用作vue的虚拟dom。本文的一个目的就是对于进入vue源码预备。
本文大致讲解,而不会完全细化至代码行数讲解
文件(以下只指出需要阅读的主要文件)
- modules
- helper
- h.js
- htmldomapi.js
- is.js
- snabbdom.js
- thunk.js
- vnode.js
vnode.js
说白了就是返回一个数据表示dom结构的数据对象
h.js
则是对多重有子结构 text节点之类的数据对象进行在再处理
返回一个解析好的vnode
htmltoapi
一些dom操作的api封装
结合到后面做vnode渲染到真实dom的操作
is.js 两个工具函数 一个是是否为数组 一个是是否为基本类型 也就是数字string这些文本节点
modules
里面放的则是一些对应的数据结构上例如property attribute之类的辅助操作
- attributes
里面用来更新节点的属性
基本的套路都是一个for in迭代 然后内部判断patch 判断是否需要更新亦或者是删除 如果存在属性的话 且不同肯定是更新 如果新有了 旧的没有就增加 新没有了旧还有 对于一些属性直接设置false 或者是赋空即可
- class.js
这里也是一些利用classList做快速增加修改删除节点上的class的操作
基本简单的判断就是这种套路
- datatset
设置节点属性值
- eventlistener
看源码可以发现 事件绑定这一步传入的参数实际上是被包装的
利用函数封装了一层handleevent
handleevent里面实际上是触发invokeHandler
那么从源码可以看出 实际上触发dom节点的绑定事件实际上是在触发
绑定在上下文为vnode的触发器上。
props设置节点这个props是需要键值对的。一般自定义属性值在这里声明好一些,设置checked selected因为内部有一个booleanarray 其实有绑定的话只是做
property能够从attribute中得到同步;
attribute不会同步property上的值;
style.js
模拟动画帧 用requestAnimationFrame不兼容则用setTimeout
requestAnimationFrame的好处是它的刷新频率会与浏览器一致
setTimeout则有时候可能出现丢失的情况
内部封装一个两层的调用来使用,大概是两帧的意思
如果没有delayed或者remove直接更新style即可
设置节点被destory时候的style
设置删除效果也就是调用自定义的remove钩子函数。如果没有的话就调用全局的
这些定义都是根据api阅读结合源码发现的
remove钩子执行后才会删除样式
snabbdom
这块是在网上看的源码解读
因为diff算法应该是一个vitrual dom实现的重点了
createKeyToOldIdx 给旧节点设置key用于比对
// create => style,class,dataset,eventlistener,props,hero
// update => style,class,dataset,eventlistener,props,hero
// remove => style
// destory => eventlistener,style,hero
// pre => hero
// post => hero
这是一些钩子函数的使用api吧
init做一些模块的初始化 还有全局钩子的初始化
emptyNodeAt
传入一个节点 然后对这个节点进行操作提取 转换成vnode数据对象
createRmCb
// remove拦截器 style里面提及的
// 对remove钩子回调做减法然后才删除节点
createElm
vnode映射真实节点
看到这里的时候对insertedVnodeQueue很不懂 究竟要干嘛
然后突然想明白了。这个大概是inserted的钩子吧- -
在每一次插入操作的时候都将节点insert
api.这类型方法可以看出来是在调用对应modules的方法
因为开始的时候就导入进来了
插入节点操作的时候都需要加入insertedVnodeQueue
子节点有子元素 也就是children的时候递归调用循环子节点生成tree
对应着一些操作之后都要触发钩子函数。
以前并不清楚钩子函数生命周期触发原理,这次倒是见识了
invokeDestroyHook 手动触发destroy钩子 先触发vnode的钩子 在触发全局钩子 再递归触发子节点的钩子
removeVnodes remove操作 因为要使得remove钩子触发后才删除节点
updateChildren patchVnode 最主要的diff算法
利用前后索引的方式
进行对两树的遍历patch 复杂度是O(n)
因为比较都是在同层做比较对比patch
起点在patchVnode 然后patch过程updateChildren 然后调用updateChildrens
一个分段的伪递归
而当索引不生效 这个时候则采用传统的key-index比对
网上的一些simple vitrual dom教程
实现的是基于深度遍历做list diff
然后取得节点的变化
在做对应操作 。
snabbdom的patch等等 都是基于数据对象做的。
而一些vitrual的实现是基于树的patch
总结
virtual-dom的一个好处就是让我们可以从繁杂无章的dom操作中解脱,利用js对象的形式映射到dom,从而操作js数据操作dom
所谓的性能其实还是得看你怎么用,大片的修改dom不见得virtual dom就有多好用。
打算也实现个simple dom 占坑~~(当然在path diff算法上可能不存在优化了)(占坑占坑)
snabbdom也是vue使用的virtual dom 库,emmm之后可以看看vue是怎么结合使用snabbdom的。
本文写于2017年05月22日
撒花。thanks
如果有需要详细代码解析的朋友可以联系我获取。
一些link
- snabbdom源码地址
- 不错的snabbdom源码解读
- 本人博客