動態組件 & 異步組件的存在,使得咱們更方便地控制首屏代碼的體積,加快加載速度。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
}
複製代碼
以後就與普通組件一致了。