异步组件
标签:异步,resolve,comp,factory,源码,vue2,组件,加载 From: https://www.cnblogs.com/dgqp/p/17360257.html
Vue
中异步组件的写法有很多,主要用作大的组件异步加载的markdown
组件editor
组件。就是先渲染一个注释标签,等组件加载完毕,最后再重新渲染forceUpdate
(图片懒加载)使用异步组件会配合webpack
原理:异步组件默认不会调用
Vue.extend()
方法 所有Ctor
上没有cid
属性,没有cid
属性就是异步组件。会先渲染一个占位符组件,但是如果有loading
会先渲染一个loading
,第一轮就结束了。如果用户调用resolve
,会将结果赋予给factory.resolve
上面,强制重新渲染。重新渲染时候再次进到resolveAsyncComponent
中,会直接拿到factory.resolve
结果来渲染.
使用
使用工厂函数:
Vue
异步组件可以通过工厂函数来定义,这个工厂函数返回一个Promise
对象,resolve
后包含一个异步组件的定义。Vue.component('async-example', function (resolve, reject) { setTimeout(function () { resolve({ template: '<div>I am async!</div>' }) }, 1000) })
使用
import()
语法Vue.component('async-webpack-example', () => import('./MyComponent.vue'))
源码实现:
function ensureCtor(comp, base) { // 如果comp已经是一个构造函数,则直接返回 if (comp.__esModule || (typeof comp === 'object' && comp.default)) { // 支持 ES2015 export default 和 module.exports 导出模块 comp = comp.default; } return isObject(comp) ? base.extend(comp) : comp; } function createAsyncPlaceholder(factory, data, context, children, tag) { const node = createEmptyVNode(); node.asyncFactory = factory; node.asyncMeta = { data, context, children, tag }; return node; } export function resolveAsyncComponent( factory: Function, baseCtor: Class<Component> ): Class<Component> | void { // 如果 factory 的类型是 Promise,则返回通过 Promise.resolve 包装过后的 factory, if (isTrue(factory.error) && isDef(factory.errorComp)) { // 如果 asyncFactory 是一个错误的异步组件工厂函数(例如因为加载组件时发生错误),则返回错误组件实例 return factory.errorComp; } // 已解决,factory 要么是一个渲染函数,要么是一个组件对象 if (isDef(factory.resolved)) { return factory.resolved; } // 这里判断异步组件是否正在加载中,如果正在加载中,则会将该异步组件在等待列表中添加一份到一个数组中, 然后直接返回继续等待 if (isDef(factory.loading) && !isDef(factory.loadingComp)) { factory.loadingComp = createAsyncPlaceholder( // 异步组件的工厂函数 factory.loading, baseCtor, undefined, undefined, undefined ); loadAndDefineAsyncComponent(factory, baseCtor); } return factory.loadingComp; } function loadAndDefineAsyncComponent(factory, baseCtor) { // 如果工厂函数是一个异步导入函数(即返回Promise的函数) if (isUndef(factory.resolved)) { // 异步加载并解析组件,同时定义一个resolve回调函数 factory.resolved = true; // 标记为已resolved factory( // 异步组件定义的成功回调 comp => { // 如果解析出来的comp是一个对象,则将其转化为Vue构造器 if (isObject(comp)) { comp = ensureCtor(comp, baseCtor); if (comp === baseCtor) { return; } } // 给异步组件定义附加上一些常用的属性 factory.resolved = comp; }, // 定义组件加载失败后的处理函数,将error和errorComp打上标记 error => { factory.error = true; factory.errorComp = ensureCtor(error, baseCtor); } ); } }
resolveAsyncComponent
方法会根据异步组件的状态返回不同的结果,如果该组件已经被解析出来,就直接返回它的构造函数;如果还在加载中,则返回一个异步占位符;如果加载出错,则返回错误组件。loadAndDefineAsyncComponent
方法则实现了异步组件的加载和定义,它使用给定的工厂函数来加载和解析组件,并在加载成功后将该组件转换为Vue
构造器。其中,工厂函数是一个异步导入函数,会返回一个Promise
对象,在resolve
回调函数中会得到异步组件的定义。