Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React系列 1- 虚拟DOM #18

Open
ZhangHanwen96 opened this issue Mar 5, 2021 · 0 comments
Open

React系列 1- 虚拟DOM #18

ZhangHanwen96 opened this issue Mar 5, 2021 · 0 comments

Comments

@ZhangHanwen96
Copy link
Owner

https://segmentfault.com/a/1190000018891454#%E8%99%9A%E6%8B%9FDOM%E5%8E%9F%E7%90%86

定义

虚拟 DOM 就是一个用于描述真实 DOM 结构的普通 JS 对象。

为什么要用虚拟dom

提高效率

使用JavaScript,我们在编写应用程序时的关注点在于如何更新DOM。

使用React,你只需要告诉React你想让视图处于什么状态,React则通过VitrualDom确保DOM与该状态相匹配。你不必自己去完成属性操作、事件处理、DOM更新,React会替你完成这一切。

这让我们更关注我们的业务逻辑而非DOM操作,这一点即可大大提升我们的开发效率。

关于性能

直接操作DOM是非常耗费性能的,这一点毋庸置疑。但是React使用VitrualDom也是无法避免操作DOM的。

如果是首次渲染VitrualDom不具有任何优势,甚至它要进行更多的计算,消耗更多的内存。

VitrualDom的优势在于React的Diff算法和批处理策略,React在页面更新之前,提前计算好了如何进行更新和渲染DOM。实际上,这个计算过程我们在直接操作DOM时,也是可以自己判断和实现的,但是一定会耗费非常多的精力和时间,而且往往我们自己做的是不如React好的。所以,在这个过程中React帮助我们"提升了性能"。

虚拟DOM转换为真实DOM

  1. 初始参数处理
  2. 批处理、事务调用
  3. 生成html

虚拟dom ---> patch更新真实dom(通过diff算法)

优点

  1. 保证性能下限: 虚拟DOM可以经过diff找出最小差异,然后批量进行patch,这种操作虽然比不上手动优化,但是比起粗暴的DOM操作性能要好很多,因此虚拟DOM可以保证性能下限
  2. 提高开发效率,无需手动操作dom
  3. 跨平台, 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。

缺点

  1. 无法极致的优化, 但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。
  2. 首次渲染时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。

setState有时候有异步的假象,由执行机制看,setState本身并不是异步的,而是如果在调用setState时,如果react正处于更新过程,当前更新会被暂存,等上一次更新执行后在执行,这个过程给人一种异步的假象。

setState =》 存储要更新的partialState到queue里 =》 是否处于batch upadte状态 =》

  • yes =》降档千组件加入组件列队

-no =》设置batch update flag为true

=》更新然后执行生命周期函数

react diff

  • 广义来讲,所谓 diff 算法就是比较两个对象结构,找到其不同的地方
  • 复杂度 n^3 --- diff O(n)
  • diff 3个策略
    • 忽略跨层级移动操作
    • 如果 2 个节点的类型不一样,以这 2 个节点为根结点的树会完全不同
    • 用key标识节点,以便复用

基于以上三个前提策略,React 分别对 tree diff、component diff 以及 element diff 进行算法优化,事实也证明这三个前提策略是合理且准确的,它保证了整体界面构建的性能。

Tree Diff

基于策略一,React 对树的算法进行了简洁明了的优化,即对树进行分层比较,两棵树只会对同一层次的节点进行比较。

https://zhuanlan.zhihu.com/p/20346379

component diff

  • 如果是同一类型的组件,按照原策略继续比较 virtual DOM tree。
  • 如果不是,则将该组件判断为 dirty component,从而替换整个组件下的所有子节点。
  • 对于同一类型的组件,有可能其 Virtual DOM 没有任何变化,如果能够确切的知道这点那可以节省大量的 diff 运算时间,因此 React 允许用户通过 shouldComponentUpdate() 来判断该组件是否需要进行 diff。

element diff

当节点处于同一层级时,React diff 提供了三种节点操作,分别为:INSERT_MARKUP(插入)MOVE_EXISTING(移动)和 REMOVE_NODE(删除)。

总结

  1. React 通过制定大胆的 diff 策略,将 O(n3) 复杂度的问题转换成 O(n) 复杂度的问题;
  2. React 通过分层求异的策略,对 tree diff 进行算法优化;
  3. React 通过相同类生成相似树形结构,不同类生成不同树形结构的策略,对 component diff 进行算法优化;
  4. React 通过设置唯一 key的策略,对 element diff 进行算法优化;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant