动态组件 & 异步组件的存在,使得咱们更方便地控制首屏代码的体积,加快加载速度。vue
抛开具体细节不谈,一个普通 Vue 组件从建立到展示在页面里,主要经历了如下流程:node
// 组件 Object
{
template: '<div>I am async!</div>'
}
// 通过 compileToFunctions 获得对应的 render function
with(this) {
return _c('div', [_v("I am async!")])
}
// 在通过 render 获得 Vnode 再 update 成为真实DOM
复制代码
动态组件&异步组件与之有什么区别呢?git
主要区别在于 render
中 createComponent
这一步,举例。github
// 组件
Vue.component('example', {
template: '<div>I am async!</div>'
})
复制代码
普通组件在 createComponent
时,会依据开发者自定义的 options
,利用 Vue.extend
生成对应的构造函数,从而获得对应的 Vnode
。而一个异步组件缓存
// 异步组件
Vue.component('async-example', function (resolve, reject) {
// 利用 setTimeout 模拟请求
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
复制代码
则是要通过一系列处理,具体过程以下dom
在源码的 create-component。异步
// async component
let asyncFactory
if (isUndef(Ctor.cid)) {
asyncFactory = Ctor
Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context)
if (Ctor === undefined) {
// return a placeholder node for async component, which is rendered
// as a comment node but preserves all the raw information for the node.
// the information will be used for async server-rendering and hydration.
return createAsyncPlaceholder(
asyncFactory,
data,
context,
children,
tag
)
}
}
复制代码
首先 Ctor
就与以前不一样,这里为一个 function
async
function (resolve, reject) {
// 利用 setTimeout 模拟请求
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
}
复制代码
以后调用 resolveAsyncComponent(asyncFactory, baseCtor, context)
函数
resolveAsyncComponent 在源码的 resolveAsyncComponent。ui
resolveAsyncComponent
的主要功能是定义 Ctor
所须要的 resolve
、reject
函数
// factory 为 Ctor
factory(resolve, reject)
复制代码
以 resolve
函数为例
const resolve = once((res: Object | Class<Component>) => {
// 缓存 resolved
factory.resolved = ensureCtor(res, baseCtor)
// 强制渲染
if (!sync) {
forceRender(true)
}
})
复制代码
once
字面理解,就是只调用一次。当 Ctor
中 setTimeout
结束时调用。
ensureCtor
就是 Vue.extend
的封装以适应不一样场景,因此 resolve
函数的主要功能就是在异步完成时,将获得的 Ctor
转化为构造函数,缓存在 factory.resolved
中。
以后利用 forceRender(true)
强制从新 render,因为以前缓存了 factory.resolved
,resolveAsyncComponent
函数就直接返回了组件的构造函数。
if (isDef(factory.resolved)) {
return factory.resolved
}
复制代码
以后就与普通组件一致了。