簡體   English   中英

來自嵌套 observables 的 Angular RXJS 輪詢

[英]Angular RXJS Polling from within nested observables

我有一個由解析器用來生成和返回報告的服務。

服務中的初始獲取調用 REST 端點/report ,它啟動服務器上的工作作業,因為報告是處理器密集型的,運行時間超過 30 秒。 report端點返回工作作業的 ID。

然后,我需要使用作業的相關 id 輪詢工人作業 REST 端點/job/job_id 我繼續輪詢,直到它返回“已完成”狀態,並包含完成的報告。

這個最終輸出然后從服務返回,解析器使用它。

我一直無法通過投票來解決這個問題。 我將初始報告端點的響應通過管道傳輸到 switchMap 中,然后使用間隔每 500 毫秒重復輪詢/job/job_id端點。 然后我嘗試切換映射投票響應並在完成時返回。 這是我第一次使用 switchMap 和輪詢,所以我不確定我是否正確使用它。

這是我對代碼的最新嘗試:

getDepartmentReport() {

  return this.http
    .get<any>(reportUrl, this.getAuthOptions(true))
    .pipe(switchMap(initialResponse => {

      interval(500).pipe(
        switchMap(() => {
          return this.http.get<any>(workerUrl + initialResponse.id, this.getAuthOptions(true))
            .pipe(
              switchMap(pollResponse => {
                if(pollResponse.state === 'completed') {
                  return pollResponse;
                }
            })
      }));
  }));
}

這實際上不會編譯。 它給出了以下錯誤:

Argument of type '(initialResponse: any) => void' is not assignable to parameter of type '(value: any, index: number) => ObservableInput<any>'.
  Type 'void' is not assignable to type 'ObservableInput<any>'.

56         .pipe(switchMap(initialResponse => {

我認為這是因為在不完整的輪詢響應時,沒有返回語句來處理這種情況,並且返回一個空值。

有人有任何想法嗎? 我難住了。

這是一個有趣的問題。

您收到該錯誤是因為switchMap必須返回一個Observable 在你的代碼中,你沒有返回任何東西,你只是開始一個間隔。

您還必須告訴您的時間間隔何時停止輪詢。 這可以在takeWhile運算符的幫助下實現。 為了將事情分開一點,我創建了一個自定義運算符,輪詢將在其中進行。 這樣做,您也可以在其他地方重用此運算符。

這是我的方法:

// ===== Server =====

let crtReportId = 1;
let crtReportStatus: { status: string, id: number };

const getReportFromBE = () => {
  let initialId = crtReportId;

  crtReportStatus = { status: 'pending', id: initialId };

  // It takes some time...
  timer(2000)
    .subscribe(() => crtReportStatus = { status: 'completed', id: initialId })

  return of(crtReportId++);
}

const getWorkerStatus = id => of(crtReportStatus);

// ===== Client =====

type CustomPollOperator = (data: any, cond: (d) => boolean, ms: number) => Observable<any>

const pollFor: CustomPollOperator = (data, cond, ms) => {
  let shouldPoll = true;

  return interval(ms)
    .pipe(
      tap(() => console.warn('pooling', shouldPoll)),
      takeWhile(() => shouldPoll),
      switchMap(() => getWorkerStatus(data)),
      tap(res => {
        if (cond(res)) {
          shouldPoll = false;
        }
      })
    )
}

const isWorkerCompleted = w => w.status === 'completed';

const getReports = () => {
  return getReportFromBE()
    .pipe(
      switchMap(workerId => pollFor(workerId,isWorkerCompleted, 200))
    )
}

getReports().subscribe((res) => console.log('result', res))

堆棧閃電戰

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM