【问题标题】:How wait for a async function in an observable?如何在 observable 中等待异步函数?
【发布时间】:2023-04-03 14:55:02
【问题描述】:

我将有一个带有 getTimeLinePosts 函数的角度服务,用于从服务器获取 JSON。在timeline-page.ts 组件中,我将订阅该功能。当向服务器发送请求时,我需要发送上一个缓存响应的日期(使用ionic cache)来检查是否有新数据。问题是 const date 返回一个承诺而不是一个值。我不能使用async getTimeLinePosts,因为在 detimeline-page.ts 中订阅。建议我如何在返回loadFromDelayedObservable 之前等待日期?

  • timeline-service.ts
getTimelinePosts(
    limit: number = 25,
    offset: number = 0,
    type: string = "",
    group: number = null
) {
    let cacheKey = `api/timeline?l=${limit}&o=${offset}&t=${type}&g=${group}`;

    // How wait for this value before fire request
    const date = this.getCachedItem(cacheKey);

    let request = this.http.post(cacheKey, { headers: HEADER.headers , params: JSON.stringify({ dateUpdated: date }) } );
    let groupKey = "timeline";
    let ttl = 60 * 60 * 1;
    let delayType = "none";

    return this.cache
        .loadFromDelayedObservable(url, request, groupKey, ttl, delayType)
        .pipe(map((result) => result));

}

    async getCachedItem(cacheKey){
        let data = await this.cache.getItem(cacheKey)
        .catch(() => {
            console.log("Oh no! My promise is expired or doesn't exist!");
        });
        return await data.data.dateUpdated;
    }
  • timeline-page.ts
this.TimelineService.getTimelinePosts(limit, offset, type, group).subscribe(
            (data) => {
                this.setTimelineData(data);
            }
        );

【问题讨论】:

    标签: angular caching promise observable ionic5


    【解决方案1】:

    这看起来像是一个结合可观察对象和承诺的典型案例。我会坚持将 promise 转换为 observable,这样我们就可以利用它的许多优势。

    您可以使用 RxJS from 函数将 promise 转换为 observable。然后,您可以使用像 switchMap 这样的高阶映射运算符从一个可观察对象映射到另一个对象。

    试试下面的

    import { from } from 'rxjs';
    import { switchMap } from 'rxjs/operators';
    
    getTimelinePosts(
        limit: number = 25,
        offset: number = 0,
        type: string = "",
        group: number = null
    ) {
        let cacheKey = `api/timeline?l=${limit}&o=${offset}&t=${type}&g=${group}`;
    
        return from(this.getCachedItem(cacheKey)).pipe(
            switchMap(date => {
                let request = this.http.post(cacheKey, { headers: HEADER.headers, params: JSON.stringify({ dateUpdated: date }) });
                let groupKey = "timeline";
                let ttl = 60 * 60 * 1;
                let delayType = "none";
    
                return this.cache
                    .loadFromDelayedObservable(url, request, groupKey, ttl, delayType)
                    .pipe(map((result) => result));
            })
        );
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用 observables - 特别是 mergeMap/flatMap,这类似于一个接一个地发送两个请求,其中第二个依赖于第一个:

      getTimelinePosts(
          limit: number = 25,
          offset: number = 0,
          type: string = "",
          group: number = null
      ) {
          let cacheKey = `api/timeline?l=${limit}&o=${offset}&t=${type}&g=${group}`;
      
          this.getCachedItem(cacheKey)
              .pipe(mergeMap((date) => {
                  let request = this.http.post(cacheKey, { headers: HEADER.headers , params: JSON.stringify({ dateUpdated: date }) } );
                  let groupKey = "timeline";
                  let ttl = 60 * 60 * 1;
                  let delayType = "none";
              
                  return this.cache
                      .loadFromDelayedObservable(url, request, groupKey, ttl, delayType)
                      .pipe(map((result) => result));
              }));
      }
      

      【讨论】: