Vitural Dom & diff算法 (一) 伪代码实现

前言:

读React 源码大概是最幸福的事情,因为在社区里有数之不尽的高手都会给出自己很独到的见解,即使有不懂的地方也会能找到前人努力挖掘的痕迹。我反问自己,然后即使在这样优越的环境下,还不去读源码,是不是就太懒了。 # 我会乱说? #

约定

这一篇都通过伪代码实现,保证首先从总体上走通流程,后面的篇章都是基于这样一个流程去实现。

开始之前

这里必须明确一个概念,所谓的 自定义标签 都是由很多原生标签诸如<div>去实现的。

因此自定义标签就可以想象成

流程

  1. 创建虚拟DOM
  2. 真实DOM 连接 虚拟DOM
  3. 视图更新
  4. 计算 [ 新虚拟DOM ] 和 [ 旧虚拟DOM ] 的差异 ( diff )
  5. 根据计算的 差异, 更新真实DOM ( patch )

这里牵涉到两个词语 diff 和 patch,稍后再解释,这里简单理解为 [计算差异]和[应用差异]。

伪代码实现

注:虽然这是这个系列的第一篇,但这已经是第二遍写了。原因是第一遍想完整模拟的时候发现,自己对算法的了解太粗浅,深搜和最短字符算法都不懂,最近和死月大大请教,所以这里偏向思路多一点。

1. 这里我们期望的真实DOM结构是这样的,下面我们一步步实现

2. 创建虚拟DOM

3. 虚拟DOM不能够影响真实DOM,这里我们需要建立连接

最终目的得到这样的字符串,可以供真实DOM使用

简单实现 ( 这里需要记录一下每个DOM的id )

这里做的事情,就是遍历虚拟DOM,然后拼合虚拟DOM后,以字符串形式输出。

4. 现在我们已经建立了连接了,现在需要模拟一下视图更新,于是我们新生成一个虚拟DOM。

注意:由于React是基于setState的方法去触发视图更新的,但这里要描述的重点是diff,因此我们简单带过。

5. 我们终于进入主题了!我们激动的去比较一下它们的差异

先别激动!

为了更好的描述这个问题,我们这里改变一下上面获取的两个虚拟DOM。

我们打算把结构换成这样的,注意注释的部分,就是两个DOM的不同之处。

6. 比较差异

6. 扁平化

为了方便比较,我们把虚拟DOM,变成Map类型的数据

8. diff

这里开始我们就正式开始比较了

这里注意到我们生成新的Map是通过 generateNewMap 方法的。 generateNewMap 实际上就是去递归调用diff,完成所有子类的差异比较,最终返回到差异数组。

7. 差异类型

这里简单用整型数字作为纪录

8. 应用差异patch

我们已经得到了所有的差异diffQueue,是时候应用这些改动了。

拿插入作例子,我们知道了挂载的对象以及插入的位置,那么我就可以用原生的insertBefore去执行。

那么通过这些计算得到的source子元素和在目标挂载元素target中的位置index,我们就能够应用这些变化。

下面简单代码再描述一下

function patch(diffQueue){

10. 大体流程再次回归
  1. diff递归找出不同,存入差异数组。每一个差异元素包含自身位置,父组件位置,差异类型
  2. 根据差异类型和差异信息,对旧的虚拟DOM作处理
  3. 所有处理结束后,一次性操作真实DOM完成处理
9. 总结

呼…虽然是第二遍写,还是不能很流畅表达,感觉抽象出来的粒度还不够,不过机智的我已经预料到了这一切。

所以第二篇会开始用算法真刀真枪去模拟整个库的形式去解读。每学习到一种解决方案还是很开心的,啦啦啦。

10. 特别推荐
  1. http://purplebamboo.github.io/

    博主貌似叫竹隐,文章质量太高了,是那种看完久久不能平复,就算是半夜都想爬起来撸代码,这篇文章就是照撸了一遍,还不够爽,第二遍自己用伪代码撸的。

  2. https://github.com/livoras/blog/issues

    抽象能力非常强,加以通俗的语言解释高深的算法,受启发好大

  3. https://github.com/Matt-Esch/virtual-dom

    权威的virtual-dom解读,看issues的讨论感觉脑洞真的好大…

  4. http://facebook.github.io/react/docs/reconciliation.html
    http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf

    官方的解读和完整的算法解释( 论文 ) …心目中前端的最终形态

1 4 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部