TransferState: кто гарантирует, что данные уже хранятся в состоянии?
Я делаю SSR с TransferState и мне интересно, кто это гарантирует, когда мы делаем
http.get(...).subscribe(data => {
transferState.set(DATA_KEY, data)
})
данные будут храниться в TransferState? Поскольку http.get является асинхронной операцией, и контент может быть сгенерирован и предоставлен клиенту без этих данных.
1 ответ
Angular Zone гарантирует, что все асинхронные операции (вызовы, отслеживаемые zone.js) будут завершены до рендеринга.
Давайте посмотрим на
server.ts
app.get('*', (req, res) => {
res.render('index', { req });
});
||
\/
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
Мы видим, что все обычные маршруты используют универсальный движок для рендеринга html.
res.render
Метод (1) определяет обратный вызов по умолчанию. Функция ngExpressEngine возвращает другую функцию с обратным вызовом, переданным в качестве параметра (2). Как только этот обратный вызов срабатывает, экспресс отправляет результат пользователю.
done = done || function (err, str) {
if (err) return req.next(err);
self.send(str);
};
Теперь давайте посмотрим, когда этот обратный вызов будет запущен. Как упоминалось ранее, нам нужно взглянуть на функцию ngExpressEngine.
getFactory(moduleOrFactory, compiler)
.then(factory => {
return renderModuleFactory(factory, {
extraProviders
});
})
.then((html: string) => {
callback(null, html);
}, (err) => {
callback(err);
});
Это произойдет только после обещания (3), возвращающегося из renderModuleFactory
функция, решена.
renderModuleFactory
функцию можно найти на @angular/platform-server
export function renderModuleFactory<T>(
moduleFactory: NgModuleFactory<T>,
options: {document?: string, url?: string, extraProviders?: StaticProvider[]}):
Promise<string> {
const platform = _getPlatform(platformServer, options);
return _render(platform, platform.bootstrapModuleFactory(moduleFactory));
}
Вы можете видеть выше, что мы на самом деле запускаем приложение Angular здесь через platform.bootstrapModuleFactory(moduleFactory)
(4)
Внутри функции _render (5) приложение ожидает завершения загрузки
return moduleRefPromise.then((moduleRef) => {
и после этого мы можем увидеть ключ для ответа:
return applicationRef.isStable.pipe((first((isStable: boolean) => isStable)))
.toPromise()
.then(() => {
Вы можете видеть, что angular universal смотрит на наблюдаемый ApplicationRef.isStable, чтобы знать, когда закончить рендеринг. Проще говоря, isStable в ApplicationRef запускается, когда у Zone нет запланированных микрозадач (7):
if (!zone.hasPendingMicrotasks) {
try {
zone.runOutsideAngular(() => zone.onStable.emit(null));