動態元件 & 非同步元件的存在,使得我們更方便地控制首屏程式碼的體積,加快載入速度。
拋開具體細節不談,一個普通 Vue 元件從建立到展現在頁面裡,主要經歷了以下流程:
// 元件 Object
{
template: '<div>I am async!</div>'
}
// 經過 compileToFunctions 得到對應的 render function
with(this) {
return _c('div', [_v("I am async!")])
}
// 在經過 render 得到 Vnode 再 update 成為真實DOM
複製程式碼
動態元件&非同步元件與之有什麼區別呢?
主要區別在於 render
中 createComponent
這一步,舉例。
// 元件
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)
})
複製程式碼
則是要經過一系列處理,具體過程如下
在原始碼的 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
function (resolve, reject) {
// 利用 setTimeout 模擬請求
setTimeout(function () {
// 向 `resolve` 回撥傳遞元件定義
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
}
複製程式碼
之後呼叫 resolveAsyncComponent(asyncFactory, baseCtor, context)
resolveAsyncComponent 在原始碼的 resolveAsyncComponent。
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
}
複製程式碼
之後就與普通元件一致了。