Vue源码之异步组件

401 阅读5分钟

工厂模式

  1. 写法
  1. 流程
  • resolveAsyncComponent 函数
  • once 函数
  1. 总结

1.首先在Vue初始化全局API时将设置的异步组件以key,value的形式(key为组件名,value为工厂函数)设置到Vue.options.components对象中。

2.在_render创建vnode阶段,碰到组件标签首先在Vue.options.components根据组件名找到对应的工厂函数赋值给Ctor,然后执行createComponent。

3.createComponent首先判断Ctor是工厂函数不是对象,不会执行构造⼦类构造函数所以也就没有cid。接着执行resolveAsyncComponent。

4.resolveAsyncComponent函数

  • 获取当前正在渲染的vm实例。
  • 标记sync为true 标识执行同步代码阶段。
  • once包装确定任何函数只执行一次 定义resolve。
  • 定义reject。
  • 执行工厂函数 发起异步组件请求。
  • 同步代码继续执行 sync设置为false。
  • 同步代码执行完毕返回undefined赋值给Ctor。

5.因Ctor此时为undefined,就返回一个空的注释vnode。

6.当工厂函数执行完成后调用resolve(res),此时res为工厂函数返回的组件export的对象,接着就会执行定义的resolve方法,首先会调用ensureCtor函数创建组件的构造函数返回赋值给factory.resolved,接着此时sync为false 会执行forceRender,forceRender会触发$forceUpdate执行vm._watcher.update()最后触发vm._update(vm._render(), hydrating)强制渲染,接着就会再次执行_render。

7._render和上面流程一样执行到resolveAsyncComponent,resolveAsyncComponent函数首先判断是否存在factory.resolved,此时是存在的,存在就直接返回。factory.resolved就是组件的构造函数接着就是创建组件的过程了。

promise

  1. 写法
  1. 流程
  • resolveAsyncComponent 函数
  1. 总结

1.首先在Vue初始化全局API时将设置的异步组件以key,value的形式(key为组件名,value为箭头函数)设置到Vue.options.components对象中。

2.在_render创建vnode阶段,碰到组件标签首先在Vue.options.components根据组件名找到对应的工厂函数赋值给Ctor,然后执行createComponent。

3.createComponent首先判断Ctor是函数不是对象,不会执行构造⼦类构造函数所以也就没有cid。接着执行resolveAsyncComponent。

4.resolveAsyncComponent函数

  • 获取当前正在渲染的vm实例。
  • 标记sync为true 标识执行同步代码阶段。
  • once包装确定任何函数只执行一次 定义resolve。
  • 定义reject。
  • 执行函数 发起异步组件请求返回promise对象。
  • 判断是promise对象设置promise的then方法。
  • 同步代码继续执行 sync设置为false。
  • 同步代码执行完毕返回undefined赋值给Ctor。

5.因Ctor此时为undefined,就返回一个空的注释vnode。

6.当promise执行完成后调用then方法的回调resolve,接着就会执行定义的resolve方法,首先会调用ensureCtor函数创建组件的构造函数返回赋值给factory.resolved,接着此时sync为false 会执行forceRender,forceRender会触发强制渲染,执行vm._watcher.update()最后触发vm._update(vm._render(), hydrating)强制渲染,接着就会再次执行_render。

7._render和上面流程一样执行到resolveAsyncComponent,resolveAsyncComponent函数首先判断是否存在factory.resolved,此时是存在的,存在就直接返回。factory.resolved就是组件的构造函数接着就是创建组件的过程了。

高级异步组件-配置化组件对象

  1. 写法
  1. 流程
  • resolveAsyncComponent 函数
  1. 总结

1.首先在Vue初始化全局API时将设置的异步组件以key,value的形式(key为组件名,value为箭头函数)设置到Vue.options.components对象中。

2.在_render创建vnode阶段,碰到组件标签首先在Vue.options.components根据组件名找到对应的工厂函数赋值给Ctor,然后执行createComponent。

3.createComponent首先判断Ctor是函数不是对象,不会执行构造⼦类构造函数所以也就没有cid。接着执行resolveAsyncComponent。

4.resolveAsyncComponent函数

  • 获取当前正在渲染的vm实例
  • 标记sync为true 标识执行同步代码阶段
  • once包装确定任何函数只执行一次 定义resolve
  • 定义reject
  • 执行函数 发起异步组件请求返回对象
  • 判断对象存在componen是个promise设置promise的then方法。
  • 有error配置创建error组件构造器,
  • 有loading配置创建loading组件构造器,判断delay是否立即执行,
  • 设置了过期时间,开启定时器,时间到了组件未resolve就调用reject
  • 同步代码继续执行 sync设置为false,
  • 同步代码执行完毕根据factory.loading判断返回loading组件构造函数还是undefined。

5.对于loading组件构造器,会先判断是否立即执行渲染loading组件,如果立即渲染就设置factory.loading = true。否则会创建延迟执行定时器,计时器到点 组件还未resolved并且不是error时再去设置factory.loading = true,然后调用forceRender强制渲染。渲染一样走到resolveAsyncComponent函数,此时就会先判断是否factory.error,是否factory.resolved,如果都不存在就返回loading组件构造器。

6.对于error组件构造器,在超时定时器中,计时器到点 组件还未resolved那么就调用reject函数。或者当promise执行完成后调用then方法的回调reject时也会调用reject函数。reject函数就会去设置factory.error = true,然后调用forceRender强制渲染。渲染一样走到resolveAsyncComponent函数,此时就会先判断是否factory.error此时为true就会返回error组件构造器。

6.对于组件构造器,当promise执行完成后调用then方法的回调resolve,接着就会执行定义的resolve方法,首先会调用ensureCtor函数创建组件的构造函数返回赋值给factory.resolved,接着此时sync为false 然后调用forceRender强制渲染。渲染一样走到resolveAsyncComponent函数,此时就会先判断是否factory.error,如果不是接着判断是否factory.resolved,此时存在就返回组件构造器。

总结

3 种异步组件的实现⽅式,看到⾼级异步组件的实现是⾮常巧妙的,它实现了 loading、resolve、reject、timeout 4 种状态。异步组件实现的本质是二次渲染,除了 0 delay 的⾼级异步组件第⼀次直接渲染成 loading 组件外,其它都是第⼀次渲染⽣成⼀个空的注释节点,当异步获取组件成功后,再通过 forceRender 强制重新渲染,这样就能正确渲染出我们异步加载的组件了。