繁体   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