-
Notifications
You must be signed in to change notification settings - Fork 9
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
20. preact源码 - diff机制 #20
Comments
@funfish 最近也在看preact源码,不太理解那边的diffLevel++具体有什么作用,因为在diff方法结尾处还是会--diffLevel。这个diffLevel貌似没可能大于1呀(除非idiff方法内部报错,导致后面的--diffLevel不能执行)。diffLevel并不能代表递归的层级,同时diffLevel还是全局可访问的变量,这个diffLevel具体是什么作用呢。还请帮忙解惑。 |
@AnthonyYY diffLevel在每次调用 diff 函数的时候都会触发自增,导致深度会大于1的。diff 函数除了在首次渲染时候会进来外,还可能会在组件渲染的时候调用。diffLevel 只是起到其是不是 0 的作用,如果是 0 的话,其最大作用就是 flushMounts 了 |
@funfish 感谢你的解答,但是我还是不明白diffLevel会在什么时候大于1.
我当前是觉得每次 |
理解了 idiff最终是会执行到diff的 |
最近preact更新了10.0.0版本,我最近看了这个版本的源码,有兴趣可以一起讨论下 |
preact 的diff 与 react 的diff 的最大区别是 preact 的diff 是会直接操作 dom嘛?而不是两个虚拟dom 比? |
前言
每次看到有人谈起 React 的 diff 机制的时候,总觉得很厉害的样子,所以自然这里也是立马就想介绍 diff 机制。
diff 机制
以下面为例子来介绍:
render 方法的实现如下:
这里面
merge
是需要对比的VNode
节点,vnode
就是传入节点,parent
则是挂载的节点。可以发现传入到render
方法里面,最终还是会调用diff
方法。看看diff
的实现:**
render
传参merge
,也就是diff
方法传参dom
,是用来和vnode
做diff
的前节点。**可以看到上面diff
方法主要作用是生成ret
,并将其挂载到parent
上面去,并在最顶部的递归层,一般componentRoot
是undefined/false
,可以执行所有已经加载的组件的componentDidMount
方法。idiff
的实现如下:这里的
idiff
方法,看着比较复杂,实际上还是对传参 vnode 进行分类判断,分为下面几种情况:这里面第一种情况是最基础的,
vnode
是文本,就要替换掉对应的dom
,第二种情况是组件的方式,这里先不谈。第三种比较麻烦,是多个子节点情况,如若dom
存在并且为文本节点,out
变量就是dom
这个文本节点,否则out
会是vnodeName
的元素空节点,随后将dom
子节点转移到out
下面。接着设置out
的__preactattr_
属性。在第三种情况时,对于前一种简答情况,如果
dom
是<div>123</div>
,而 vnode 的 children 属性为文本的话,例如:vnode = {nodeName: 'SPAN', Children: ['sb'].....}
,则生成的out
为<span>sb</span>
,这种是简单的情况。复杂情况下需要调用到innerDiffNode
方法。在介绍innerDiffNode
之前,先看看idiff
方法最下面的diffAttributes
方法:diffAttributes
方法就是将vnode
里面attribute
和props
属性添加到out
里面,最后返回的是out
元素而不是 vnode!setAccessor
基本就是些条件语句,根据出入的属性名,来分类处理,看看就好了。就这样将 vnode 里面的attribute
属性添加到out
里面。innerDiffNode
idiff
第三种情况的复杂情况下下会调用innerDiffNode
方法,实际上就是对vnode
的子元素和out
的子元素进行递归对比。先看看innerDiffNode
的实现:innerDiffNode
的目的就是要vnode
的每个vchild
和能与其对应上的out
下面的child
进行对比,也就是调用diff
方法,从而实现子节点之间的对比。在innerDiffNode
里面对比找出child
的过程,看上面代码中的解释就好了。在通过idiff
方法生成新的child
后,child
会被加入到out
里面。从而一步步将vnode
的children
移入作为out
的节点。在遍历了所有的vnode
的children
之后,还需要对下面两种out
的子节点移除:key
属性的节点,如果没有匹配上 vnode 的 children ,需要移除;总结
diff 机制基本就是不断的遍历子节点和 vnode,来实现对比不同。将 vnode 里面的内容添加到 dom 里面,而将 dom 里面不需要的多余的子节点移除掉。所以这里还需要理解整体的移除机制,以及组件生成对比的机制,将在下篇文章里面介绍到。
The text was updated successfully, but these errors were encountered: