最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    正文概述 掘金(借你趁早)   2021-02-05   428

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    学习snabbdom有助于拓宽我们对虚拟DOM的认知。当下最流行之一的Vue,它的虚拟DOM技术就源于snabbdom。

    作者最近最近学习了snabbdom,并手写snabbdomd的核心部分,GitHub地址:study_snabbdom 不到300行

    有兴趣可以拉下来看看,有详细注解和学习说明,将持续更新配图。

    ├─study_snabbdom                 
        ├─app
        │	└─index.html       # 静态的html模板
        ├─src                        # 项目源代码
        │    ├─snabbdom              # 手写源码的文件目录
        │    │  ├─createElement.js   # 虚拟dom对象定义
        │    │  ├─h.js               # 将表达式转换成以对象简单定义的dom
        │    │  ├─htmldomapi.js      # 操作DOM方法的简单封装
        │    │  ├─patch.js           # 开启diff的入口
        │    │  ├─updateChildren.js  # diff算法最核心的部分。
        │    │  ├─vnode.js           # 返回虚拟节点的模块
        │    ├─index.js              # 入口文件
        └─package.json               # 
        └─RMEADME.md                 # 
        └─webpack.config.js          # webpack 配置
    

    不过今天要讨论的不是如何手写snabbdom库的核心内容。而是想说说在它官方GitHub的文档上唯一的一个常见错误,“为什么不允许在patch时重用虚拟节点

    由于Vue的虚拟DOM和diff算法核心和snabbdom几乎是一样的,所以讨论它就像是在讨论Vue。

    一、为了说明什么这个问题,需要对虚拟DOM和diff算法有一个基本的了解。

    (1)真实的DOM以li标签为例,它至少有200个属性

    我知道就算你无所谓什么是virtual DOM和diff算法,也不想在调试栏中点开这个玩意儿。

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    (2)Virtual DOM最少只需要5个属性

    virtual DOM就是一个用JS对象来表示一个真实DOM最重要的特征。

    {
      children: undefined    // 一个数组 ,存放子虚拟DOM
      data: {key: "A"}	 // 一个对象 ,用于存放一些属性和key,
      elm: li	         // ⭐一个引用 , 对应自身的真实DOM引用(如果在DOM树上的话)?
      key: "A"               // 一个字符串 , 用于标识自己
      sel: "li"              // 一个字符串 , 用于表明自身的 tagName
      text: "A2"             // 一个字符串 , 通常是本文属性值
    }
    @以上就是构成一个虚拟DOM的最小可能。
    

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    (3)虚拟DOM中的diff算法是通过比对两个虚拟DOM,找出它们的差异再进行较少次数DOM操作的一个算法。

    一般遵循以下原则

    1. 同层比较 。 比如。

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    2. 同节点比较 。 比如。

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    二、回到正题,为什么不允许重用虚拟节点呢?

    1、我们对patch()做一个实验。

    (1)对html中那个容器进行patch。

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    开场一首苏轼的《水调歌头》window.onload完成调一个 patch()

    window.onload  = function (){
    	patch(container, newVnode1)
    }
    

    第1次patch 把《水调歌头》修改成了A B C D E。

    (2)接下点击按钮2,对刚刚newVnode1进行patch

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    window.onload  = function (){
    	btn.onclick = patch(newVnode1,newVnode2)
    }
    

    第2次patch 把 A B C D E 修改成了B2 A2 C2 E2 D2。

    (3)接下点击按钮1,对刚刚newVnode2进行patch,并传入newVnode1作为第2参数

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    第3次patch 把 B2 A2 C2 E2 D2 修改成了A C D E。

    这时候发现少了一个 B 。??

    2、起初我以为这是我的代码逻辑有问题。但是使用源码也是一样

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    通过在代码中输出信息,发现无论是源码还是我手写的实现,输出的位置时间和内容都是一致的。

    3、答案就在于 diff核心算法,updateChildren函数中。

    4中常规命中方式失败之后,会通过查找的方式,来搜寻旧节点中是否有新节点,如果正好有,而且是同 key 同 sel就会继续对这两个节点调用patch(),调用完成后会为这个旧子节点的elm打上 undefined的标识 。

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    因此,当重用虚拟节点去patch的时候,就可能出现某一个虚拟节点的elm属性已经是undefined了。

    重点来了,由于网络上diff算法都用文字说明,看着太费解了作者自己做了动图,并且在图里找到了答案。

    本图是仓库的配图,虽然和例子不一样,但是足以说明。

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点? (这里把旧子节点列表同时当成真实DOM来演示,可以把它们看成是一致的。)

    看看第2次patch和第3次patch后,虚拟节点的情况。

    【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    可以看到第2次patch之后,newVnode1虚拟节点列表中下标为1的元素已经是undefined了,第3次patch之后,newVnode2中下标 1 2也是undefined了。因此当你再使用这个虚拟节点调用patch的时候,肯定会发生意外。

    一些心得

    DOM中的diff是算法为了减少DOM操作的次数。它在比较的时候,是对虚拟DOM进行比较,而将真实DOM的引用保存在虚拟DOM的elm属性中,并在发生差异时才操作DOM。

    官方的解释

    常见错误

    Uncaught NotFoundError: Failed to execute 'insertBefore' on 'Node':
        The node before which the new node is to be inserted is not a child of this node.
    
    var vnode2 = h('div', [
      h('div', {}, ['One']),
      h('div', {}, [{ ...sharedNode }]),
      h('div', {}, ['Three']),
    ])
    
    var sharedNode = () => h('div', {}, 'Selected')
    var vnode1 = h('div', [
      h('div', {}, ['One']),
      h('div', {}, ['Two']),
      h('div', {}, [sharedNode()]),
    ])
    

    起源地下载网 » 【自说自话】为什么在snabbdom(Vue)中不允许在patch时重用虚拟节点?

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元