🚩Исходный код Vue — как использовать асинхронные компоненты

Vue.js

В последнее время я участвовал во многих интервью, и почти в каждом интервью будут задавать вопросы об исходном коде Vue. Я открою здесь серию столбцов, чтобы обобщить опыт в этой области.Если вы считаете, что это полезно для вас, пожалуйста, поставьте лайк и поддержите это.

предисловие

в предыдущем посте🚩 Исходный код Vue — как регистрируются и используются компонентыВ ней подробно описан внутренний логический поток регистрации и использования компонентов, а также регистрация и использование синхронных компонентов. Но в реальной разработке часто используются асинхронные компоненты. Давайте сначала посмотрим, как зарегистрировать асинхронные компоненты в официальной документации, которую можно разделить на три способа.

  • Обычный функциональный асинхронный компонент
Vue.component('aa', function(resolve, reject) {
    setTimeout(function() {
        resolve({
            template: '<div><p>{{aa}}<span>{{bb}}</span></p></div>',
            data() {
                return {
                    aa: '欢迎',
                    bb: 'Vue'
                }
            }
        })
    }, 1000)
})
  • Обещание асинхронного компонента
Vue.component('aa', () => import('./aa.js') )
  • Расширенные асинхронные компоненты
const aa = () => ({
    // 需要加载的组件。应当是一个 Promise
    component: import('./aa.vue'),
    // 加载中应当渲染的组件
    loading: LoadingComp,
    // 出错时渲染的组件
    error: ErrorComp,
    // 渲染加载中组件前的等待时间。默认:200ms。
    delay: 200,
    // 最长等待时间。超出此时间则渲染错误组件。默认:Infinity
    timeout: 3000
})
Vue.component('aa', aa)

Как видно из приведенного выше примера, поVue.componentЗарегистрированный компонент больше не объект, а функция, которая является не конструктором компонента, а фабричной функцией. Эта фабричная функция имеет два параметраresolveфункция иrejectФункция, которая определена внутри Vue.В этой фабричной функции есть асинхронная функция, которая вызывается при успешном выполнении асинхронной функции.resolveФункция, аргументом которой является объект асинхронного компонента.

Из предыдущего поста🚩 Исходный код Vue — как регистрируются и используются компоненты, вы можете узнать об использовании компонента, вы должны сначалаvm._renderвыполнение процессаvnode = createComponent(Ctor, data, context, children, tag)генерироватьvnode, где параметрCtorМожет быть функцией или объектом, начиная сcreateComponentМетоды начинают описывать, как используются асинхронные компоненты.

function createComponent(Ctor, data, context, children, tag) {
    if (isUndef(Ctor)) {
        return
    }
    var baseCtor = context.$options._base;
    if (isObject(Ctor)) {
        Ctor = baseCtor.extend(Ctor);
    }
    if (typeof Ctor !== 'function') {
        return
    }
    // async component
    var asyncFactory;
    if (isUndef(Ctor.cid)) {
        asyncFactory = Ctor;
        Ctor = resolveAsyncComponent(asyncFactory, baseCtor);
        if (Ctor === undefined) {
            return createAsyncPlaceholder(asyncFactory, data, context, children, tag)
        }
    }
    data = data || {};
    resolveConstructorOptions(Ctor);
    installComponentHooks(data);
    var name = Ctor.options.name || tag;
    var vnode = new VNode(
        ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')),
        data, undefined, undefined, undefined, context, {
            Ctor: Ctor,
            tag: tag,
            children: children
        },
        asyncFactory
    );
    return vnode
}

когда параметрCtorТип значения - функция, она не будет выполнятьсяCtor = baseCtor.extend(Ctor).

Потому что в Vue это называетсяVue.extendметод для создания конструктора компонента, который наследует Vue. существуетVue.extendбудет казненSub.cid = cid++для конструктора компонентаcidуступка имущества.

var cid = 1;
Vue.extend = function(extendOptions) {
    var Sub = function VueComponent(options) {
        this._init(options);
    };
    Sub.prototype = Object.create(Super.prototype);
    Sub.prototype.constructor = Sub;
    Sub.cid = cid++;
    return Sub
}

Таким образом, вы можете использоватьisUndef(Ctor.cid)судитьCtorне является конструктором компонента, если не выполняетCtor = resolveAsyncComponent(asyncFactory, baseCtor)Введите логику, используемую асинхронными компонентами, давайте сначала посмотримresolveAsyncComponentфункция.

function resolveAsyncComponent(factory, baseCtor) {
    if (isTrue(factory.error) && isDef(factory.errorComp)) {
        return factory.errorComp
    }
    if (isDef(factory.resolved)) {
        return factory.resolved
    }
    var owner = currentRenderingInstance;
    if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
        factory.owners.push(owner);
    }
    if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
        return factory.loadingComp
    }
    if (owner && !isDef(factory.owners)) {
        var owners = factory.owners = [owner];
        var sync = true;
        var timerLoading = null;
        var timerTimeout = null;
        (owner).$on('hook:destroyed', function() {
            return remove(owners, owner);
        });
        var forceRender = function(renderCompleted) {
            for (var i = 0, l = owners.length; i < l; i++) {
                (owners[i]).$forceUpdate();
            }
            if (renderCompleted) {
                owners.length = 0;
                if (timerLoading !== null) {
                    clearTimeout(timerLoading);
                    timerLoading = null;
                }
                if (timerTimeout !== null) {
                    clearTimeout(timerTimeout);
                    timerTimeout = null;
                }
            }
        };
        var resolve = once(function(res) {
            factory.resolved = ensureCtor(res, baseCtor);
            if (!sync) {
                forceRender(true);
            } else {
                owners.length = 0;
            }
        });
        var reject = once(function(reason) {
            warn(
                "Failed to resolve async component: " + (String(factory)) +
                (reason ? ("\nReason: " + reason) : '')
            );
            if (isDef(factory.errorComp)) {
                factory.error = true;
                forceRender(true);
            }
        });
        var res = factory(resolve, reject);
        if (isObject(res)) {
            if (isPromise(res)) {
                if (isUndef(factory.resolved)) {
                    res.then(resolve, reject);
                }
            } else if (isPromise(res.component)) {
                res.component.then(resolve, reject);

                if (isDef(res.error)) {
                    factory.errorComp = ensureCtor(res.error, baseCtor);
                }
                if (isDef(res.loading)) {
                    factory.loadingComp = ensureCtor(res.loading, baseCtor);
                    if (res.delay === 0) {
                        factory.loading = true;
                    } else {
                        timerLoading = setTimeout(function() {
                            timerLoading = null;
                            if (isUndef(factory.resolved) && isUndef(factory.error)) {
                                factory.loading = true;
                                forceRender(false);
                            }
                        }, res.delay || 200);
                    }
                }
                if (isDef(res.timeout)) {
                    timerTimeout = setTimeout(function() {
                        timerTimeout = null;
                        if (isUndef(factory.resolved)) {
                            reject(
                                "timeout (" + (res.timeout) + "ms)"
                            );
                        }
                    }, res.timeout);
                }
            }
        }
        sync = false;
        return factory.loading ? factory.loadingComp : factory.resolved
    }
}

resolveAsyncComponentЭто высокоуровневая функция, которая в основном обрабатывает различные фабричные функции при регистрации асинхронных компонентов, параметры фабричных функций определяются внутри.resolveфункция иrejectфункция и вызвала фабричную функцию, успешно выполненнуюresolveфункция, не удалось выполнитьrejectфункция, которая, наконец, возвращает конструктор компонента или undefined.

Принцип регистрации асинхронных компонентов и синхронных компонентов одинаков, но принцип использования асинхронных компонентов отличается от принципа использования синхронных компонентов. Разберем и представим принцип использования асинхронных компонентов поочередно по трем методам регистрации асинхронных компонентов.

1. Обычные функциональные асинхронные компоненты

Vue.component('aa', function(resolve, reject) {
    setTimeout(function() {
        resolve({
            template: '<div><p>{{aa}}<span>{{bb}}</span></p></div>',
            data() {
                return {
                    aa: '欢迎',
                    bb: 'Vue'
                }
            }
        })
    }, 1000)
})

resolveAsyncComponent(factory, baseCtor),параметрfactoryЗначение указано вышеVue.componentВторой параметр , параметрbaseCtorэто Вью Конструктор. Организуйте код и удалите код, который не имеет ничего общего с этой сценой.

function resolveAsyncComponent(factory, baseCtor) {
    if (isDef(factory.resolved)) {
        return factory.resolved
    }
    var owner = currentRenderingInstance;
    if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
        factory.owners.push(owner);
    }
    if (owner && !isDef(factory.owners)) {
        var owners = factory.owners = [owner];
        var sync = true;
        (owner).$on('hook:destroyed', function() {
            return remove(owners, owner);
        });
        var forceRender = function(renderCompleted) {
            for (var i = 0, l = owners.length; i < l; i++) {
                (owners[i]).$forceUpdate();
            }
            if (renderCompleted) {
                owners.length = 0;
            }
        };
        var resolve = once(function(res) {
            factory.resolved = ensureCtor(res, baseCtor);
            if (!sync) {
                forceRender(true);
            } else {
                owners.length = 0;
            }
        });
        var reject = once(function(reason) {
            warn(
                "Failed to resolve async component: " + (String(factory)) +
                (reason ? ("\nReason: " + reason) : '')
            );
        });
        var res = factory(resolve, reject);
        sync = false;
        return factory.loading ? factory.loadingComp : factory.resolved
    }
}

существуетresolveAsyncComponentВ функции внутренне определены три функцииforceRender,resolve,reject. вresolveа такжеrejectФункцияonceФункциональная обертка.

function once(fn) {
    var called = false;
    return function() {
        if (!called) {
            called = true;
            fn.apply(this, arguments);
        }
    }
}

onceФункция — это функция более высокого порядка, искусно использующая замыкания иcalledпеременная, чтобы убедиться, что обернутая функция выполняется только один раз. то есть обеспечитьresolveа такжеrejectФункция выполняется только один раз.

Потому чтоresolveAsyncComponentпоследняя выполненная функцияreturn factory.loading ? factory.loadingComp : factory.resolved,вернутьfactory.resolved.

Так что взглянитеfactory.resolved, который определен вresolveв функции.

var resolve = once(function(res) {
    factory.resolved = ensureCtor(res, baseCtor);
    if (!sync) {
        forceRender(true);
    } else {
        owners.length = 0;
    }
})

воплощать в жизньensureCtor(res, baseCtor)после назначенияfactory.resolved, посмотриensureCtorметод.

function ensureCtor(comp, base) {
    if (
        comp.__esModule ||
        (hasSymbol && comp[Symbol.toStringTag] === 'Module')
    ) {
        comp = comp.default;
    }
    return isObject(comp) ?
        base.extend(comp) :
        comp
}

параметрbaseДля конструктора Vue, наконец, выполнитеreturn isObject(comp) ? base.extend(comp) : comp, если параметрcompэто объект, который выполняетbase.extend(comp), то есть выполнитьVue.extend(comp)Создайте конструктор, который наследует Vue.

параметрcompчерезresolveаргументы функцииresПрошедший. назадresolveAsyncComponentметод, выполняетvar res = factory(resolve, reject)этот код,factoryчерезVue.componentВторой параметр параметра пропускается, и значение выглядит следующим образом.

function(resolve, reject) {
    setTimeout(function() {
        resolve({
            template: '<div><p>{{aa}}<span>{{bb}}</span></p></div>',
            data() {
                return {
                    aa: '欢迎',
                    bb: 'Vue'
                }
            }
        })
    }, 1000)
}

вresolveто естьresolveAsyncComponentопределяется внутри функцииresolveфункция. тогда параметрcompЗначение , как показано ниже, является объектом опций компонента.

{
    template: '<div><p>{{aa}}<span>{{bb}}</span></p></div>',
    data() {
        return {
            aa: '欢迎',
            bb: 'Vue'
        }
    }
}

сделай этоensureCtor(res, baseCtor)получит конструктор компонентов, затемfactory.resolvedЗначением является конструктор компонента.

назад сноваcreateComponentметод, посмотрите на этот код

Ctor = resolveAsyncComponent(asyncFactory, baseCtor);
if (Ctor === undefined) {
    return createAsyncPlaceholder(asyncFactory, data, context, children, tag)
}

воплощать в жизньresolveAsyncComponentПосле того, как метод возвращает конструктор компонента для назначенияCtor. Это конец? Конечно нет, интересно, заметили ли выVue.componentВо втором заданном параметреresolve(//...)Есть еще один внешний слойsetTimeoutТаймер — это асинхронная задача. JavaScript является однопоточным, и асинхронные задачи не могут выполняться до тех пор, пока не будут выполнены все синхронные задачи. Поэтому в это времяresolveAsyncComponentв методеresolveфункция не выполняется,factory.resolvedДолжно быть неопределенным. ТакCtorне определено, выполнитьreturn createAsyncPlaceholder(asyncFactory, data, context, children, tag).createAsyncPlaceholderметод используется для создания узла комментарияvnodeв качестве заполнителя.

function createAsyncPlaceholder(factory, data, context, children, tag) {
    var node = createEmptyVNode();
    node.asyncFactory = factory;
    node.asyncMeta = {
        data: data,
        context: context,
        children: children,
        tag: tag
    };
    return node
}

В настоящее времяcreateComponentУзел аннотации, сгенерированный методомvnode, вместо компонентаvnode, как визуализировать компонент, не волнуйтесь, вернитесь кresolveAsyncComponentметод, выполняемый перед возвратомsync = falseЧерез 1000 мсresolveфункция выполняетсяforceRender(true), посмотриforceRenderфункция.

var resolve = once(function(res) {
    factory.resolved = ensureCtor(res, baseCtor);
    if (!sync) {
        forceRender(true);
    } else {
        owners.length = 0;
    }
})
var owner = currentRenderingInstance;
if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
    factory.owners.push(owner);
}
if (owner && !isDef(factory.owners)) {
    var owners = factory.owners = [owner];
    var forceRender = function(renderCompleted) {
        for (var i = 0, l = owners.length; i < l; i++) {
            (owners[i]).$forceUpdate();
        }
        if (renderCompleted) {
            owners.length = 0;
        }
    };
}

currentRenderingInstanceтекущий экземпляр Vue, использующий асинхронный компонент, назначенныйowner.

Если один и тот же асинхронный компонент зарегистрирован локально во многих местах. Это будет повторяться много раз одно и то жеresolveфункция. Итак, вот оптимизация.

Асинхронный компонент — это фабричная функцияfactoryопределить компоненты, вfactoryопределить свойствоowners, чтобы сохранить текущий экземпляр Vue с помощью асинхронных компонентов, т. е. вызовfactoryКонтекст функции.

подобноownerиметь ценность иfactory.ownersне существует, значитfactoryФункция выполняется впервые. подобноownerиметь ценность иfactory.ownersценность, значитfactoryФункция уже выполнена. воплощать в жизньfactory.owners.indexOf(owner) === -1судитьfactory.ownersЕсть ли текущий экземпляр Vue, если нет, добавьте текущий экземпляр Vue вfactory.ownersсередина.

назадforceRenderфункция, выполнение(owners[i]).$forceUpdate()довольно производительныйvm.$forceUpdate()этот метод экземпляра. Это связано с тем, что данные не изменяются во время процесса загрузки асинхронного компонента, поэтому при выполненииvm.$forceUpdate()Заставьте экземпляр Vue выполнить повторный рендеринг один раз.

Vue.prototype.$forceUpdate = function() {
    var vm = this;
    if (vm._watcher) {
        vm._watcher.update();
    }
}

воплощать в жизньvm._watcher.update()довольно производительныйmountComponentв методеvm._update(vm._render(), hydrating), выполнениеvm._render()вызов процессаcreateComponentМетод по очереди выполняет следующую логику.

// async component
var asyncFactory;
if (isUndef(Ctor.cid)) {
    asyncFactory = Ctor;
    Ctor = resolveAsyncComponent(asyncFactory, baseCtor);
    if (Ctor === undefined) {
        return createAsyncPlaceholder(asyncFactory, data, context, children, tag)
    }
}

выполнить сноваresolveAsyncComponent(asyncFactory, baseCtor), прошло 1000 мс, значит фабричная функция зарегистрирована асинхронным компонентомfactoryсерединаresolveФункция выполнена, значитfactory.resolvedЕсли есть значение, вернитесь напрямуюfactory.resolved.

function resolveAsyncComponent(factory, baseCtor) {
    if (isDef(factory.resolved)) {
        return factory.resolved
    }
}

возвращаемое значениеfactory.resolvedявляется конструктором асинхронного компонента, назначеннымCtor,CtorПосле получения значения сгенерируйте компонентvnode, а затем выполнитьvm._update, введите процесс исправления и замените исходный узел аннотации заполнителя компонента реальным содержимым DOM компонента. Процесс исправления обновления компонента здесь не представлен, и отдельная глава будет представлена ​​позже. Теперь, когда был представлен принцип использования асинхронных компонентов общих функций, давайте представим принцип использования асинхронных компонентов Promise.

2. Обещайте асинхронные компоненты

Vue.component('aa', () => import('./aa.js') )

resolveAsyncComponent(factory, baseCtor),параметрbaseCtorэто Вью Конструктор. параметрfactoryЗначение указано вышеVue.componentВторой параметр , возвращаемое значениеimport('./aa.js'), который является объектом Promise. Организуйте код и удалите код, который не имеет ничего общего с этой сценой.

function resolveAsyncComponent(factory, baseCtor) {
    if (isDef(factory.resolved)) {
        return factory.resolved
    }
    var owner = currentRenderingInstance;
    if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
        factory.owners.push(owner);
    }
    if (owner && !isDef(factory.owners)) {
        var owners = factory.owners = [owner];
        var sync = true;
        (owner).$on('hook:destroyed', function() {
            return remove(owners, owner);
        });
        var forceRender = function(renderCompleted) {
            for (var i = 0, l = owners.length; i < l; i++) {
                (owners[i]).$forceUpdate();
            }
            if (renderCompleted) {
                owners.length = 0;
            }
        };
        var resolve = once(function(res) {
            factory.resolved = ensureCtor(res, baseCtor);
            if (!sync) {
                forceRender(true);
            } else {
                owners.length = 0;
            }
        });
        var reject = once(function(reason) {
            warn(
                "Failed to resolve async component: " + (String(factory)) +
                (reason ? ("\nReason: " + reason) : '')
            );
            if (isDef(factory.errorComp)) {
                factory.error = true;
                forceRender(true);
            }
        });
        var res = factory(resolve, reject);
        if (isObject(res)) {
            if (isPromise(res)) {
                if (isUndef(factory.resolved)) {
                    res.then(resolve, reject);
                }
            }
        }
        sync = false;
        return factory.loading ? factory.loadingComp : factory.resolved
    }
}

Поскольку в этом сценарии фабричная функцияfactoryВозвращаемое значение является объектом Promise, поэтому удовлетворяетisObject(res)а такжеisPromise(res)условие, выполните следующую логику

if (isUndef(factory.resolved)) {
    res.then(resolve, reject);
}

Поскольку возвращенный объект Promise, его метод экземпляраthenАргумент является функцией двухresolveа такжеreject. будет выполняться в случае успехаresolveФункция при неудачных вызовахrejectфункция.

Итак, вот умная реализацияres.then(resolve, reject), когда выполнение будет успешным, он упадетresolveфункция, и этоresolveфункция, даresolveAsyncComponentобычай в функции. Следующая логика точно такая же, как у обычного асинхронного компонента функции.

3. Расширенные асинхронные компоненты

В расширенных асинхронных компонентах вы можете определить компоненты, отображаемые при загрузке асинхронного компонента, и компоненты, отображаемые при сбое загрузки, что более удобно для пользователя.

const aa = () => ({
    // 需要加载的组件。应当是一个 Promise
    component: import('./aa.vue'),
    // 加载中展示的组件
    loading: LoadingComp,
    // 加载失败展示的组件
    error: ErrorComp,
    // 渲染加载中组件前的等待时间。默认:200ms。
    delay: 200,
    // 最长等待时间。超出此时间则渲染错误组件。默认:Infinity
    timeout: 3000
})
Vue.component('aa', aa)

resolveAsyncComponent(factory, baseCtor),параметрbaseCtorэто Вью Конструктор. параметрfactoryЗначение указано вышеVue.componentВторой параметр, возвращаемое значение — это объект. Организуйте код и удалите код, который не имеет ничего общего с этой сценой.

function resolveAsyncComponent(factory, baseCtor) {
    if (isTrue(factory.error) && isDef(factory.errorComp)) {
        return factory.errorComp
    }
    if (isDef(factory.resolved)) {
        return factory.resolved
    }
    var owner = currentRenderingInstance;
    if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
        factory.owners.push(owner);
    }
    if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
        return factory.loadingComp
    }
    if (owner && !isDef(factory.owners)) {
        var owners = factory.owners = [owner];
        var sync = true;
        var timerLoading = null;
        var timerTimeout = null;
        (owner).$on('hook:destroyed', function() {
            return remove(owners, owner);
        });

        var forceRender = function(renderCompleted) {
            for (var i = 0, l = owners.length; i < l; i++) {
                (owners[i]).$forceUpdate();
            }

            if (renderCompleted) {
                owners.length = 0;
                if (timerLoading !== null) {
                    clearTimeout(timerLoading);
                    timerLoading = null;
                }
                if (timerTimeout !== null) {
                    clearTimeout(timerTimeout);
                    timerTimeout = null;
                }
            }
        };

        var resolve = once(function(res) {
            factory.resolved = ensureCtor(res, baseCtor);
            if (!sync) {
                forceRender(true);
            } else {
                owners.length = 0;
            }
        });

        var reject = once(function(reason) {
            warn(
                "Failed to resolve async component: " + (String(factory)) +
                (reason ? ("\nReason: " + reason) : '')
            );
            if (isDef(factory.errorComp)) {
                factory.error = true;
                forceRender(true);
            }
        });

        var res = factory(resolve, reject);

        if (isObject(res)) {
            if (isPromise(res.component)) {
                res.component.then(resolve, reject);
                if (isDef(res.error)) {
                    factory.errorComp = ensureCtor(res.error, baseCtor);
                }
                if (isDef(res.loading)) {
                    factory.loadingComp = ensureCtor(res.loading, baseCtor);
                    if (res.delay === 0) {
                        factory.loading = true;
                    } else {
                        timerLoading = setTimeout(function() {
                            timerLoading = null;
                            if (isUndef(factory.resolved) && isUndef(factory.error)) {
                                factory.loading = true;
                                forceRender(false);
                            }
                        }, res.delay || 200);
                    }
                }

                if (isDef(res.timeout)) {
                    timerTimeout = setTimeout(function() {
                        timerTimeout = null;
                        if (isUndef(factory.resolved)) {
                            reject(
                                "timeout (" + (res.timeout) + "ms)"
                            );
                        }
                    }, res.timeout);
                }
            }
        }

        sync = false;
        return factory.loading ? factory.loadingComp : factory.resolved
    }
}

Поскольку в этом сценарии фабричная функцияfactoryВозвращаемое значение является объектомres,

если средиres.componentСвойство представляет собой объект Promise, который выполняетсяres.component.then(resolve, reject).

подобноres.errorзначение, выполнитьfactory.errorComp = ensureCtor(res.error, baseCtor), преобразуйте отображаемый компонент, загрузив сбой в конструктор компонента, и назначьте егоfactory.errorComp.

подобноres.loadingзначение, выполнитьfactory.loadingComp = ensureCtor(res.loading, baseCtor), преобразуйте компонент, отображаемый при загрузке, в конструктор компонента и назначьте егоfactory.loadingComp.

подобноres.delayЗначение 0 указывает, что компонент загрузки должен отображаться напрямую, аfactory.loadingУстановите значение true .

подобноres.delayне равно 0, это означает, что через периодdelayКомпонент загрузки отображается только после временной задержки, а таймер setTimeout используется через определенный период времени.delayВременная задержка в случае, если асинхронный компонент не загружается успешно или дает сбойfactory.loadingустановите значение true и выполнитеforceRender(false), процесс исправления, запускающий обновление компонента, отображает компонент, отображаемый при загрузке.

подобноres.timeoutИмеет значение, используйте setTimeout по истечении времени таймераres.timeoutПосле того, как асинхронный компонент не был загружен, сообщается об ошибке тайм-аута.

Наконец, при загрузке в конструктор компонентаfactory.loadingвозвращаемое значениеfactory.loading, вам не нужно звонитьcreateAsyncPlaceholderМетод создает узел комментария в качестве узла-заполнителя и напрямую использует узел DOM, сгенерированный компонентом, отображаемым при загрузке, в качестве узла-заполнителя.

Асинхронные компоненты визуализируются во время процесса исправления обновления компонента и будут вызываться снова.resolveAsyncComponentметод.

if (isTrue(factory.error) && isDef(factory.errorComp)) {
    return factory.errorComp
}
if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
    return factory.loadingComp
}

подобноfactory.errortrue и не удалось загрузить конструктор компонентаfactory.errorCompсуществует, возвращаетсяfactory.errorComp.

подобноfactory.loadingtrue и загрузка конструктора компонентовfactory.loadingCompсуществует, возвращаетсяfactory.loadingComp.

Загрузка асинхронного компонента успешно завершаетсяfactory.resolved, следующая логика точно такая же, как и у обычного асинхронного компонента функции.

Наконец, мы представим обработку, когда асинхронный компонент не загружается, что вызовет пользовательскийrejectфункция, еслиfactory.errorComp,Пучокfactory.errorустановить на истину. затем выполнитьforceRender(true)В это время его параметр верно, а таймеры в нагрузке и время ожидания загрузки могут быть очищены во время принудительного рендеринга.

4. Резюме

Существует 3 способа реализации асинхронных компонентов Vue, среди которых расширенные асинхронные компоненты реализуют 4 состояния загрузки, разрешения, отклонения и тайм-аута. Суть реализации асинхронного компонента — 2 рендеринга, кромеdelayЗа исключением первого раза, когда расширенный асинхронный компонент 0 отображается непосредственно в компоненте загрузки, остальные визуализируются в первый раз для создания узла комментария.resolveфункция, в которой можно вызватьforceRenderФункция вызывает повторный рендеринг, второй вызовresolveAsyncComponentфункция, которая возвращает конструктор реального компонентаfactory.resolvedА затем асинхронный компонент может быть представлен через процесс обновления компонентов.