Angular,在部分可选时是否需要嵌套Observable?

时间:2018-03-22 21:47:19

标签: angular observable

我对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

2 个答案:

答案 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

请注意,我没有订阅,并且消费者应该是订阅者。