Data Service 使用

我目前有一個資料處理服務 如圖取值方式可以透過訂閱或get的方法獲取

我打算在進入某個組件前透過 resolve 方式預先取得資料
因此在這個類注入 DataService 獲取資料 但我打算透過 Rx 來處理 如附圖

不知道為什麼 就是不會轉跳到組件內 整個程式就卡死
但如果在 這邊寫

    let test= know.subscribe(data => console.log(data));
    console.log(test);

是可以正常獲取資料的

目前的解法有兩種 一種是透過 subject 本身的 value 屬性取值 另一種是 先訂閱

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    return this.courseService.getGetCourseDetail(this.authService.getCurrentAccountInfo(), this.courseDataService.getClassId())
      .pipe(catchError((err) => this.router.navigateByUrl('/')));
  }

先訂閱

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    let classId;
    this.courseDataService.classId.subscribe(data => classId = data);
    let know = this.courseService.getGetCourseDetail(this.authService.getCurrentAccountInfo(), classId);
    return know;
  }

上述兩者都可以 不過我印象中是不建議這麼做吧…?
既然都是兩個流都是可觀察物件 那是不是透過第一種方式比較好 但又不能轉跳 我苦惱好久還是不知道原因
希望版上的人能幫忙 :joy::joy::joy:

使用 resolver 要注意回傳的 observable 是否會結束,如果沒有 complete 的一天,resolver 就不會結束

在這你使用 BehaviorSubject <= 預設沒有停止的一天,這也是造成你無法轉址的原因

1個讚

但是我在 後面補上
let cool = know.subscribe(data => console.log(data));
console.log(cool);
是能夠打印出來結果 是因為我這裡先訂閱了 也就 complete了 所以能拿到結果
但是 我再把 know 當作 observable return 回去
因為 BehaviorSubject 預設不會 complete 所以他就卡著不動了?

BehaviorSubject 的行為是,在訂閱時,會先輸出最後一次的值,但是並沒有結束
所以當下一個 next 發生時,就又會收到新的資料

只要是 Subject 類的,只要你沒有手動去 complete, 他就會一直活著

那為什麼我直接呼叫 this.courseService.getGetCourseDetail 這也是可觀察物件
classId 直接給了 外部方法再去訂閱 就不會卡死?

如果是透過我上述的程式 switMap 不是取得當下 DataService 中 BehaviorSubject 裡面最後一筆 classId 在進行呼叫 this.courseService.getGetCourseDetail 就會卡死 是因為他沒有 complete ??

還是沒有搞懂…

要回到 resolve 的行為是什麼? 他要怎麼知道什麼時候可以進續路由轉址的動作?

show一下 sourceService.getGetCourseDetail 的程式碼吧

程式如下

  getGetCourseDetail(loginRqu: AccountInfo, classId: string): Observable<CourseDetail> {

    let req = Object.assign({}, loginRqu, {ClassID: classId});

    return this.apiService.get('/GetCourseDetail', new HttpParams({ fromString: `strAccess=${this.getStrAccess(req)}` }))
    .map(res => {
      let courseDetail = res as ApiResponse<CourseDetail>;
      return (courseDetail.success) ? courseDetail.data['0'] : null;
    });
  }

resolve 的行為是在進入組件實例化前的動作 他要怎麼知道繼續路由轉跳
這件事情我還真沒搞懂…

return this.apiService.get('/GetCourseDetail',...)

這裡的行為是會結束的.

Resolve 需要一個會結束的 observable 的說明在此 (連結)

The CrisisService.getCrisis method returns an observable, in order to prevent the route from loading until the data is fetched. The Router guards require an observable to complete, meaning it has emitted all of its values.

我要怎麼理解是否能 complete?
因為使用 angular 內建的 httpclient 提供的 get 方法 本身就發出請求拿到 response 後
就會執行 complete 嗎?

而 BehaviorSubject 本身特性的關係 並不會 complete
訂閱後會發向訂閱者發出上次快取住的最後一個值 除非訂閱者有重新 set 值才會觸發 complete ??

感覺越來越不懂了…
謝謝管理員熱心回應

Angular 內的 http.get 方法,只會呼叫一次,呼叫完就結束了. 這是內建的行為

RxJS 的 Observable 有三階段, next, error 和 complete,當 Observable 一旦進入 error 或是 complete 時,該 observable 就已經完成他的工作了

Subject 也是 observable,所以也會有上述的三個階段,只是說 subject 可以透過 .next() .error 和 .complete 等方式來控制所處階段

而我們可以透過一些 oeprators 來進行 complete 的動作,例如 take.

建議先建立一個簡單的環境,先熟悉一下 subject 的特性

2個讚

再次獻上感謝管理員 最終程式如下

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    return this.courseDataService.classId.pipe(
      take(1),
      switchMap(classId => {
        return this.courseService.getGetCourseDetail(this.authService.getCurrentAccountInfo(), classId);
      }),
      catchError((err) => this.router.navigateByUrl('/'))
    );
  }

總算是能理解為什麼卡死的原因了 連帶之前學習關於
[译] RxJS: 别取消订阅
Angular/RxJs When should I unsubscribe from Subscription
這下內心的謎團也解開了 都是透過 subject 的特性 搭配 take操作符 觸發 complete 來結束監聽的感覺

那如果本身使用的是 Angular 內的 httpclient.get 方法 似乎也不用多此一舉?
因為本身就只會呼叫一次? 所以也不需要在乎取消訂閱和 memory leak 的問題?

1個讚

推薦你閱讀這篇文章

1個讚

同一篇文章 只是我看的是譯文 :joy: