網站搜尋

typescript - RxJS 處理閉包變數


我的情境如下:- 連接到資料庫以取得某個物件 - 獲取基本物件後,擷取它的附加資料 - 將附加資料合併到基本物件

我希望以純函數方式來撰寫它(即沒有副作用),但到目前為止我還無法做到:

getMeterPointWithMeterDatabyId(id: number, allowEmpty: boolean = false): Observable<MergeObject> {
    const params = this.getEmptyParams();
    let mp: MergeObject; // This is my enclosed objects I refer to

    return this.masterService.getMasterById(params)
    .concatMap<MergeObject, MergeData[]>((master: MergeObject) => {
      mp = master; // This is side effect generation
      return this.meterService.getMasterData(params);
    })
    .concatMap<MasterData[], MergeObject>((md: MasterData[]) => {
      mp.data = md.slice(); // Even more side effects
      return Observable.of(mp); // Final result generated form impure result
    });

我認為我對在物件之間沒有循環依賴時 Rx 的運作方式有很好的理解(即我的呼叫鏈產生了 A -> B -> C),但當我需要在某個處理步驟回頭抓取一些先前的資料時,我就開始失去信心(即 A -> B -> A,其中 A 最終包含 B)。

編輯:據我所知,zip 運算符可以達到這個效果,但我想知道,是否有可能手動實現這個功能

答案#1

如果你實際上需要基礎物件來查詢細節(也就是說,請求必須連續發生),你可以這樣做

this.service.getMaster(id)
  .switchMap(master => this.service.getDetails(master)
    // .catch(…) <-- if you want to continue even if fetching the details fails
    .map(details => merge(master, details))
  )
  .subscribe();

技巧是簡單地將 map 嵌套在 switchMap 中,這樣 master 就可以保持在作用域內,而不需要費心琢磨其他方法。

如果明細請求實際上是獨立的,你可以使用以下方式同時啟動兩者

Observable.forkJoin(
  this.service.getMaster(id),
  this.service.getDetails(id)
    // .catch(…) <-- if you want to continue even if fetching the details fails
)
  .map(([master, details) => merge(master, details))
  .subscribe();

將操作鏈非線性化的技術,也就是轉換

source$
  .switchMap(data1 => transformationA(data1))
  // From here on out, you only see data1
  .switchMap(data2 => transformationB(data2))
  // From here on out, you only see data2
  .subscribe(data3 => …);

進入

source$
  .switchMap(data1 => transformationA(data1)
    .switchMap(data2 => transformationB(data2)
    // You can see both data1 and data2 here!
  )
  .subscribe(data3 => …);

經常用來保持多個步驟的數據在作用域內,例如將它們結合起來。這絕對是需要時刻記住的事情:你也可以嵌套使用。