工厂模式
- 写法
- 流程
- resolveAsyncComponent 函数
- once 函数
- 总结
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
- 写法
- 流程
- resolveAsyncComponent 函数
- 总结
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就是组件的构造函数接着就是创建组件的过程了。
高级异步组件-配置化组件对象
- 写法
- 流程
- resolveAsyncComponent 函数
- 总结
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 强制重新渲染,这样就能正确渲染出我们异步加载的组件了。