Angular2:嵌套订阅与循环内的第二个订阅

Angular2: Nested subscribe with second subscribe inside the loop

我刚接触 Angular2 一周!

基本上有2个API调用。

  1. 第一个 API 调用为我提供了 json 个对象的数组 (queryResults)。 (第 1 次订阅)
  2. 在视图中显示该数组。
  3. 遍历 (queryResults) 数组并从每个数组元素 (queryResults[i].oldLastSeen) 中选择一个特定的键值对。
  4. 将该值 (oldLastSeen) 作为请求参数传递给另一个 API,它会给我一个字符串 (newLastSeen)。 (第二次订阅)
  5. 用queryResult中的newLastSeen替换oldLastSeen

由于 Observable 的异步性质,问题出现在第 5 步。我无法在内部订阅中访问 queryResults[i].oldLastSeen 并且基本上是未定义的。因此 lastSeen 不会更新。

开始调用 getLastSeen(), 代码如下所示:

temp: any[];
rows: any[];

getLastSeen() {
    this._someService.getQueryResults(this.query)
      .subscribe(queryResults => {
        this.rows = queryResults;
        this.updateLastSeen(this.rows);
      });
}

private updateLastSeen(rows) {
    this.temp = rows; //temp: any[];
    for(var i=0; i<this.temp.length; i++) {
        if(this.temp[i].id != null || this.temp[i].oldLastSeen != null) {
            //Some operations here
            this._someService.getNewLastSeen(this.temp[i].oldLastSeen)
                .subscribe(
                    newLastSeen => {
                        this.rows[i].oldLastSeen = newLastSeen; //This doesnot happen!
                    },
                    error => alert(error),
                    () => console.log("Finished.")
                );
        }
    }
  }

两天以来一直在敲我的头,遇到了 flatMap、switchMap 等。但对它们的用法非常怀疑。

更新:工作代码:

我听取了 Bryan 的反馈,并对他建议的代码进行了一些修改。这是对我有用的:

this._someService.getQueryResults(this.query)
      .do(qr => {this.rows = qr;})
      .flatMap(queryResults => Observable.from(queryResults))
      .filter(queryItem => queryItem["id"] != null || queryItem["oldLastSeen"] != undefined)
      .do(queryItem => { // did some operations/ manipulations here})
      .mergeMap(queryItem => this._someService.getNewLastSeen(this.queryItem["oldLastSeen]),
           (queryItem, newLastSeen) => [queryItem, newLastSeen])
      .subscribe(([queryItem, newLastSeen]) => {
        queryItem.oldLastSeen = newLastSeen
      }); 

一般来说,如果您有嵌套订阅,那么您正在处理一个可以改进的反模式。我还没有找到一个令人信服的案例来使用它。我不确定对 flatMap 或 switchMap 持怀疑态度意味着什么,但它们是非常有用的运算符,尤其是 switchMap。如果你的工具包中没有 switchMap,你将无法做超出 rxjs 基础知识的事情。

getLastSeen() {
    this._someService.getQueryResults(this.query)
      .do(qr => this.rows = qr;)
      .flatMap(queryResults => Observable.from(queryResults))
      .filter(queryItem => queryItem.id !== null || queryItem.oldLastSeen !== null)
      // you can insert a map or do operator here to accomplish the operations you mention, depending on what they are, or you can possibly just do them inside switchMap
      .switchMap(queryItem => this._someService.getNewLastSeen(queryItem.oldLastSeen),
           (queryItem, newLastSeen) => [queryItem, newLastSeen])
      .subscribe(([queryItem, newLastSeen]) => queryItem.oldLastSeen = newLastSeen);

}

一块一块地看:

  1. 你得到你的查询

  2. 您将结果设置到视图中。功能纯粹主义者会说在这里这样做是不好的做法,因为它会产生副作用,但无论如何。我不是纯粹主义者。

  3. 这很棘手,但您正在将结果扁平化为可观察的数据流。您从结果数组创建一个可观察对象,然后 flatmap 一个一个地发出它们,您也可以在这里使用 .mergeAll() 。这是一种更具反应性的循环结果方式。

  4. 过滤掉您不感兴趣的项目

  5. 你的 "operations" 的占位符行,也许是映射或做,在不知道想要的效果的情况下很难说。也可能只是在 switchMap 中可行,但要注意样式和保持运算符简洁。

  6. switchMap 进入新的 observable,switchMap 将订阅内部 observable 并发出结果,关键是 switchMap 的第二个参数,它允许您将内部和内部的项目组合起来外部可观察的。在这里我们只是将它们放入一个数组并发出两个值的数组

  7. 重置订阅中的项目。这里唯一有趣的是使用打字稿语法,让您可以命名数组中的项目,因为您知道您正在获得一个包含 2 个项目的数组。