由于AppConfiguration
应该是所有路由共享的单例,因此有两种常见的模式可以做到这一点。
考虑到解析器的一个主要好处是访问从异步解析器解包的数据activatedRoute.snapshot.data.resolverName
,一种方法是使用由所有解析器解包的单例服务,例如:
@Injectable()
class Config {
data: IConfig;
data$: Observable<IConfig>;
constructor(private http: Http) {}
load(forceReload = false) {
if (!this.data$ || forceReload) {
this.data$ = this.http.get('...')
.map(res => res.json())
.do(data => {
this.data = data
})
.publishReplay(1)
.refCount();
}
return this.data$;
}
}
load
方法返回一个带有缓存的服务器响应的 observable,该响应在功能上等同于一个 Promise。但是由于已知可观察对象是由路由器本机使用的,因此在这种情况下使用它们是很自然的。
然后所有解析器都可以返回config.load()
并确保请求只执行一次(除非它被称为 like config.load(true)
):
@Injectable()
class ConfigResolver {
constructor(private config: Config) {}
resolve() {
return this.config.load();
}
}
...
{ path: ..., component: ... resolve: { config: ConfigResolver } }
可以使代码 DRYer 并提供一个函数或一个类来config
为所有路由添加解析器,但不建议这样做,因为这种方法与 AoT 不兼容。在这种情况下,WETter 更好。
另一种方法是使用文档记录不佳的APP_INITIALIZER
提供程序,此问题中对此进行了详细说明。虽然路由解析器推迟路由更改,APP_INITIALIZER
但以相反的方式工作并推迟应用程序初始化。
它是多提供者,应该在根注入器中定义:
export function configInitializerFactory(config: Config) {
return () => config.load();
}
@NgModule({
...
providers: [
...
Config,
{
provide: APP_INITIALIZER,
useFactory: configInitializerFactory,
deps: [Config],
multi: true
}
]
})
...
无需涉及解析器,因为数据在应用初始化期间已经解析。
幸运的是,data$
observable 已经被解包到data
in 中Config
,因此解析的数据在注入时已经可用config.data
.