sameVnode 中的 isAsyncPlaceholder
来源:5-7 组件更新(1)

zhc青
2020-11-23
老师好,在vue 2.6.12 版本中研究了一下 sameVnode 方法中关于的 isAsyncPlaceholder 属性的逻辑,有些想法和疑惑想和您讨论一下。
function sameVnode (a, b) {
a.key === b.key && (
... || (
isTrue(a.isAsyncPlaceholder) &&
a.asyncFactory === b.asyncFactory &&
isUndef(b.asyncFactory.error)
)
}
疑惑
关于 isAsyncPlaceholder
的描述,视频5-6中4分16秒说的“异步占位符结点”,电子书是“异步组件会进行判断”。
我查看了代码后感觉是错误的,原因在于 isAsyncPlaceholder
表示的是“异步组件的占位符结点中的一个子集类型”,而不是“异步占位符 ”或者“异步组件”。(不知道是不是 Vue 版本问题)
ps:个人理解中,“异步占位符” 是异步组件加载前的占位结点,并不是异步组件。
理由
isAsyncPlaceholder 在 VNode 初始化时是直接赋值为false。所以不论是什么组件,isAsyncPlaceholder 最开始都为 false。
constructor() {
// ... 省略
this.isAsyncPlaceholder = false
}
而把 isAsyncPlaceholder 赋值为 true 的地方共两个:
-
patchVnode 时。赋值为true的前提条件时 oldVnode 中的 isAsyncPlaceholder 为
true
,因为初始化 vnode 时该值都为false
,所以排除这块内容。 -
调用 hydrate 方法时。
hydrate 方法只在除自身递归外共两处调用:
-
在patchVnode时,和上述一样的原因,该地方被排除。
-
在 patch 时调用 。调用前提是
hydrating
为 true。该值是在 $mount 方法的第二个参数,默认为undifined。而把 hydrating 赋值为 true 是在下列代码:
if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
oldVnode.removeAttribute(SSR_ATTR)
hydrating = true
}
其中判断了是否具有 SSR_ATTR
的自定义属性…
又因为 hydrating 属性在是在 $mount 是一层层传下去的,而 $mount 的调用可能来自 new Vue 时传了 el 属性让 Vue 自动调用,此时的hydrating一定为 undefined。
所以猜测 isAsyncPlaceholder 只有在 ssr 渲染时才会赋值给“异步占位符”。
补充:组件钩子的 init 方法也会调用 $mount,但是 createComponent 时,会传入false
if (isDef(i = i.hook) && isDef(i = i.init)) {
i(vnode, false /* hydrating */)
}
总结
总结一下上述理由:
isAsyncPlaceholder 默认为 false,第一个结点修改为 true 的地方只有一个。修改前提是 hydrating 为 true。而 hydrating 默认是false,置为 true 的条件之一是需要在 SSR 渲染。
所以得出 isAsyncPlaceholder 代表的不是“异步组件” 或 “异步占位符”。而是“SSR渲染下,异步组件的占位符的一个子集类型”(子集类型的的具体描述我没研究…且和ssr相关,暂时不准备看这块内容 )。
ps: 太难了,不知道老师能否理解我的意思 :(
1回答
-
首先为你细致的研究源码精神点赞,我也大致看了一遍,isAsyncPlaceholder 理解为异步组件的占位符这点从语义上理解没有太大的问题。
hydrate 可以翻译成注水,这个过程就是专为 ssr 设计的,那么 ssr 做了什么事情呢,其实相比 csr 而言,就是在服务端也跑一遍 Vue.js 代码,生成 HTML 模板,然后在客户端执行的过程中,除了渲染组件外,还要执行 hydrate 注水过程,所以在 ssr 的时候 $mount 第二个参数为 true。
hydrate 的过程是不需要再次创建 DOM 的,因为页面早就创建好了。
那么在 hydrate 的时候,执行到 patch 方法,检测到
if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {
vnode.isAsyncPlaceholder = true
return true
}
满足这俩条件说明这个 vnode 就是一个异步组件的占位符节点,因为在创建异步组件的过程中,会先创建一个注释 vnode,并且这个 vnode 的 asyncFactory 指向它的工厂方法。
综上,isAsyncPlaceholder 的意义还是代表异步占位符,只是执行这段代码的逻辑是配合 SSR 渲染执行的。012020-11-23
相似问题