异步组件的写法大致三种,一种是require语法,一种是es6的import语法,另一个是高级异步组件
// 全局注册:
Vue.component('component1', function(resolve) {
require(['./aa.vue'], resolve)
})
Vue.component('component2', () => import('./aa.vue'))
// 局部注册:
var vm = new Vue({
el: '#app',
template: '<div id="app"><asyncComponent></asyncComponent></div>',
components: {
component1: (resolve) => require(['./aa.vue'], resolve),
component2: () => import('./aa.vue'),
}
})
针对全局注册,执行Vue.component,由于传入的definition是一个工厂函数,不是对象,所以这一步啥也没做,但是 this.options[type + 's'][id] = definition;这一步还是会执行的,会在Vue的component下定义一个函数。
当我们创建组件Vnode时,执行createComponent时,由于异步组件没cid然后执行resolveAsyncComponent函数,然后执行传入的工厂函数 var res = factory(resolve, reject);
resolve做了一层once封装,主要是为了只执行一次
function once (fn) {
var called = false;
return function () {
if (!called) {
called = true;
fn.apply(this, arguments);
}
}
}
执行工厂函数,回去异步加载组件,由于js是同步的,所以会继续执行,返回undefined,继续执行
createComponent中的逻辑,执行createAsyncPlaceholder会返回一个注释节点
当异步组件加载完成之后,执行resolve函数,ensureCtor适配不同加载方式,然后返回一个构造器。然后执行forceRender,强制刷新
然后又会走相同逻辑,因为没cid,同上,执行resolveAsyncComponent,执行到判断factory.resolved,由于第二次是有值的,会直接返回,后续同正常逻辑
使用es6的import加载同上,只是由于返回值是promise,会执行res.then
高级异步组件写法如下。
Vue.component('asyncComponent', () => ({
// 需要加载的组件 (应该是一个 `Promise` 对象)
component: import('./MyComponent.vue'),
// 异步组件加载时使用的组件
loading: LoadingComponent,
// 加载失败时使用的组件
error: ErrorComponent,
// 展示加载时组件的延时时间。默认值是 200 (毫秒)
delay: 200,
// 如果提供了超时时间且组件加载也超时了,
// 则使用加载失败时使用的组件。默认值是:`Infinity`
timeout: 3000
}))
返回值的component是promise就进入高级异步组件逻辑分支,主要是了error
和loading
组件,会同时创建两个子类的构造器,后续会根据不同场景去加载