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 的地方共两个:

  1. patchVnode 时。赋值为true的前提条件时 oldVnode 中的 isAsyncPlaceholder 为 true,因为初始化 vnode 时该值都为 false ,所以排除这块内容。

  2. 调用 hydrate 方法时。

hydrate 方法只在除自身递归外共两处调用:

  1. 在patchVnode时,和上述一样的原因,该地方被排除。

  2. 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回答

ustbhuangyi

2020-11-23

首先为你细致的研究源码精神点赞,我也大致看了一遍,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 渲染执行的。

0
1
zhc青
原来如此。一开始看电子书,以为异步组件都会走下面的逻辑。研究了好一会才发现是在ssr下的,然后就怀疑人生了。感谢老师解答~ ?
2020-11-23
共1条回复

Vue.js 源码深入解析 深入理解Vue实现原理

全方位讲解 Vue.js 源码,进阶高级工程师

4984 学习 · 1037 问题

查看课程