TransferState: кто гарантирует, что данные уже хранятся в состоянии? - PullRequest
0 голосов
/ 19 декабря 2018

Я делаю SSR с TransferState и задаюсь вопросом, кто гарантирует, что когда мы сделаем

http.get(...).subscribe(data => {
  transferState.set(DATA_KEY, data)
})

данные будут сохранены в TransferState ?Поскольку http.get является асинхронной операцией , и содержимое может быть сгенерировано и предоставлено клиенту без этих данных.

1 Ответ

0 голосов
/ 25 декабря 2018

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(() => {

Вы можете видеть, что угловой универсальный взгляд на ApplicationRef.isStable , наблюдаемый, чтобы знать, когда закончить рендеринг.Проще говоря, isStable on ApplicationRef запускается, когда Зона не имеет запланированных микрозадач (7):

if (!zone.hasPendingMicrotasks) {
  try {
    zone.runOutsideAngular(() => zone.onStable.emit(null));

enter image description here

...