我对Angular有点新,最后对Observables的正确使用感到困惑。我甚至无法提出具体的问题,所以我必须以迂回的方式来做。
tl; dr:我认为问题归结为:我如何同步相互依赖的请求,但仅在需要时?在执行任务之前是懒惰加载的先决条件(可能是Observables)只是不好的练习,我应该在appstart上加载每个可能的先决条件吗?
/ TL:博士
故事: 对于自动完成输入字段,我想使用API来提供建议。我还不知道URI,我必须首先请求一个ApiConfig,它告诉我URI。
所以我想要一次请求配置,多次请求建议。
这就是我现在所拥有的,但我不喜欢,我每次都必须致电getSearchModuleUri()
并且建议请求在其订阅正文中。在我看来,它不是分层的,因为uri比实际的关键GET请求更重要。
getSuggestions: Observable<SearchResult[]>(searchTerm: string) {
return this.getSearchModuleUri().subscribe(searchUri => this.http.get<SearchResult[]>(searchUri));
}
getSearchModuleUri(): Observable<string> {
//magical stuff - equal to Observable.of('http://host/api/foo')
return uriAsObservable();
}
}
我有一个类变量,一旦我检索到它就会保存searchUri:
searchUri: string;
getSuggestions: Observable<SearchResult[]>(searchTerm: string) {
this.getSearchModuleUri();
return this.http.get<SearchResult[]>(searchUri));
}
getSearchModuleUri(): Observable<string> {
//still magical stuff - equal to Observable.of('http://host/api/foo')
if(searchUri){
//do nothing
}
else{
//get the uri and set it in the class variable
uriAsObservable().subscribe(retrievedUri => this.searchUri = retrievedUri);
}
}
如果需要,请求uri,如果没有,请使用它。我知道这不会那样工作,因为可观测量是异步的,searchUri
不能及时准备好。但这就是我所寻找的,有没有办法,没有自举并在应用程序启动时请求所有可能的配置?
只要没有多层可观察物,它们就会变得既简单又容易。 但是当请求可能具有某些先决条件或先决条件时,我不知道如何处理它们。
如果我的建议请求需要3个或5个参数,该怎么办?我是否真的必须做某些事情(有点伪代码)getTertiaryParam1().subscribe(getNotSoInterestingParam2().subscribe(getParamofDoom3().subscribe(getUri().subscribe(getSuggestions(uri,p1,p2,p3,....,pN)))))
?即使大多数这些参数在设置一次时是不变的吗?
我无法想象的另一个例子是如何将这样的请求与所需的OAuth2身份验证相结合。什么时候我的OAuth拦截器,我的令牌无效,我必须事先发出一个refreshToken请求,等待新的令牌,然后发送实际的建议请求与有效的授权?我可能事先检查一下,必要时修好,然后继续。
如果你现在还没想到,我在功能编程方面没有太多经验。我敢肯定,在问题上投入适量的flatMap和switchMaps会解决一些问题,但就像现在一样,我被困住了。
如果你做得那么远,甚至可能理解我的问题,非常感谢你的时间!
最好的问候,Manu
答案 0 :(得分:1)
您可以使用ReplaySubject缓存Uri。然后它只被查询一次:
private uriCache: ReplaySubject<string>;
getSuggestions(searchTerm: string): Observable<SearchResult[]> {
return this.getSearchModuleUri()
.switchMap(uri => this.http.get<SearchResult[]>(searchUri));
}
getSearchModuleUri(): Observable<string> {
//still magical stuff - equal to Observable.of('http://host/api/foo')
if(!this.uriCache){
this.uriCache = new ReplaySubject<string>(1);
Observable
.of('http://host/api/foo')
.subscribe(uri => this.uriCache.next(uri));
}
return this.uriCache.asObservable();
}
最后,您可以使用switchMap从源Observable映射到下一个Observable并返回生成的Observable。
如果要在请求之前解析多个参数,可以使用Observable.zip,Observable.combineLatest或类似的东西来检索参数并映射到最终请求。 在使用javascript http调用时,反应式编程是一个关键概念。
答案 1 :(得分:-1)
首先,您认为将结果存储在类中一次是一个好主意,然后只需访问缓存的结果。
Angular中有一个专用令牌可以帮助您实现这一目标:hdistance([H|T], [H|T1], Distance) ->
hdistance(T, T1, Distance + 1);
hdistance([H|T], [H1|T1], Distance) ->
hdistance(T, T1, Distance).
它不仅应该被你使用(如果你需要,也可以使用其中的许多),这就是为什么在使用它时你应该通过// add datatype to your ajax call
$.ajax({
url: '/get_data',
dataType: 'json',
type: 'POST',
data: myFormData,
success: function(data){
var items = '';
$.each(data, function (i, item) {
// build your html here and append it to your .modal-body
var label = "<label>" + item.MyProperty+ "</label>"
$('div.modal-body').append(label);
});
}
});
财产到APP_INITIALIZER
:
multi
现在,您持有配置的类应该如下所示:
true
现在,在应用程序进行bootraped之前,它会等待加载配置。然后你只需要注入类并调用同步的@NgModule({
...
providers: [
// your class holding the configuration
AppConfig,
{
provide: APP_INITIALIZER,
useFactory: (config: AppConfig) => config.loadConfig().toPromise(),
deps: [AppConfig],
multi: true
}
]
})
export class AppModule { }
。
对于观察者来说,永远不要,永远不要做以下事情:
@Injectable()
export class AppConfig {
private config: any;
constructor(private http: HttpClient) {}
public loadConfig(): Observable<any> {
return this.http
.get('https://jsonplaceholder.typicode.com/posts/1')
.pipe(tap(config => (this.config = config)));
}
public getConfig() {
return this.config;
}
}
首先,通过订阅您的流,您不返回Observable,您返回订阅。打字稿应该抛出错误。
如果从Observable的响应中你需要触发另一个,请使用switchMap或flatMap:
appConfig.getConfig
请注意,我没有订阅,并且消费者应该是订阅者。