TransferState:谁能保证数据已经存储在状态中?

时间:2018-12-19 15:04:11

标签: angular angular-universal angular-transfer-state

我正在使用TransferState进行 SSR , 想知道谁能保证我们这样做

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

数据将存储在 transferState 吗? 因为 http.get是异步操作,并且可以生成内容并将其提供给客户端而无需此数据。

1 个答案:

答案 0 :(得分:7)

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)定义default callbackngExpressEngine函数返回作为参数(2)传递的another function with that callback。回调一旦触发,express就会将结果发送给用户。

done = done || function (err, str) {
  if (err) return req.next(err);
  self.send(str);
};

现在让我们看看何时callback will be triggered。如前所述,我们需要查看ngExpressEngine函数。

 getFactory(moduleOrFactory, compiler)
   .then(factory => {
       return renderModuleFactory(factory, {
          extraProviders
       });
    })
    .then((html: string) => {
      callback(null, html);
    }, (err) => {
      callback(err);
}); 

只有在从renderModuleFactory函数返回的promise(3)被解析之后,这种情况才会发生。

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));
}

您可以在上方看到我们实际上通过platform.bootstrapModuleFactory(moduleFactory)(4)运行Angular应用程序

内部_render函数(5)应用程序等待bootstrapping to be finished

return moduleRefPromise.then((moduleRef) => {

然后我们可以看到the key作为答案:

return applicationRef.isStable.pipe((first((isStable: boolean) => isStable)))
        .toPromise()
        .then(() => {

您可以看到,ApplicationRef.isStable的角度通用观察可以知道何时完成渲染。简单来说,Zone has no microtasks scheduled(7)会触发ApplicationRef上的isStable:

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

enter image description here