Vue 動態組件 & 異步組件原理

動態組件 & 異步組件的存在,使得咱們更方便地控制首屏代碼的體積,加快加載速度。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

主要區別在於 rendercreateComponent 這一步,舉例。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 就與以前不一樣,這裏爲一個 functionasync

function (resolve, reject) {
    // 利用 setTimeout 模擬請求
    setTimeout(function () {
        // 向 `resolve` 回調傳遞組件定義
        resolve({
            template: '<div>I am async!</div>'
        })
    }, 1000)
}
複製代碼

以後調用 resolveAsyncComponent(asyncFactory, baseCtor, context)函數

resolveAsyncComponent 在源碼的 resolveAsyncComponentui

resolveAsyncComponent 的主要功能是定義 Ctor 所須要的 resolvereject 函數

// factory 爲 Ctor
factory(resolve, reject)
複製代碼

resolve 函數爲例

const resolve = once((res: Object | Class<Component>) => {
    // 緩存 resolved
    factory.resolved = ensureCtor(res, baseCtor)
    // 強制渲染
    if (!sync) {
    	forceRender(true)
    }
})
複製代碼

once 字面理解,就是隻調用一次。當 CtorsetTimeout 結束時調用。

ensureCtor 就是 Vue.extend 的封裝以適應不一樣場景,因此 resolve 函數的主要功能就是在異步完成時,將獲得的 Ctor 轉化爲構造函數,緩存在 factory.resolved 中。

以後利用 forceRender(true) 強制從新 render,因爲以前緩存了 factory.resolvedresolveAsyncComponent 函數就直接返回了組件的構造函數。

if (isDef(factory.resolved)) {
    return factory.resolved
}
複製代碼

以後就與普通組件一致了。

相關文章
相關標籤/搜索