Angular 4.3 Observables:如何重试间隔和最大重试次数?

时间:2017-10-15 11:30:48

标签: angular observable

我是Angular 4.3的新手。我有一个地图应用程序,用于呈现"地图图层"通过下载一系列小图像(" tile")。在启动时,地图图层可能需要0.1到5.0秒才能下载。

当客户端收到两个或多个磁贴时,我需要触发一个事件。我以为我可以通过订阅一个Observable来实现这个目标,它可以在200ms的间隔内重试30次。

到目前为止:

  public updateTileContainer() {
    this._getTileContainer().subscribe(container => {
      if (container) {
        console.log('* do stuff with container *');
      }
    });
  }

  private _getTileContainer(): Observable<any> {

    return Observable.interval(200)
      .mergeMap(function (n) {

        const tileImages = $('#mymap').find('img[src*=\'kml\']');

        console.log(`Retry ${n}: ${tileImages.length} tiles found`);

        if (!tileImages || tileImages.length < 2) {
          return Observable.of(null);
        }

        const tileContainer = getContainer(tileImages);

        return Observable.of(tileContainer);
      })
      .take(30);
  }

这个有效!有点。我得到了这个输出:

Retry 0: 0 tiles found
Retry 1: 0 tiles found
Retry 2: 0 tiles found
Retry 3: 0 tiles found
Retry 4: 0 tiles found
Retry 5: 0 tiles found
Retry 6: 0 tiles found
Retry 7: 2 tiles found
* do stuff with container *
Retry 8: 3 tiles found
* do stuff with container *
Retry 9: 9 tiles found
* do stuff with container *
Retry 10: 12 tiles found
* do stuff with container *
etc.

我实际上要做的是发出一个事件,在&#34;重试7&#34;,然后停止发射。

如何更改为&#34;完成&#34;我一找到容器就会观察到Observable?我怎样才能跳过&#34;为重试0到6发出事件,因为它们不是真正的事件?如果在没有找到容器的情况下进行30次重试,我可以从Observable中抛出错误吗?

4 个答案:

答案 0 :(得分:3)

使用.retry(count)

如果您的选择中的图块少于2个,则可以抛出错误。然后retry() 30次。

NB:在第30次重试后,实际会发出错误,您需要处理它。但这可能是一件好事(见进一步说明)。

public updateTileContainer() {
  this._getTileContainer().subscribe(container => {
      console.log('* do stuff with container *');
  },error=>{
      console.log('no container found !');
  });
}

private _getTileContainer(): Observable <any> {
  return Observable.timer(200).map(()=>{
    const tileImages = $('#googlemap').find('img[src*=\'kml\']');
    if (tileImages.length <= 2)
      throw new Error("not enough tiles !");
    return getContainer(tileImages);
  })
  .retry(30);
}

您的解决方案和@JonStødle的工作正常。但请注意,如果您无法获得任何容器,则不会收到通知。实际上,如果找不到容器,Observable就完成了,没有错误。

如果您想知道您无法找到容器,处理错误可能是一件好事。

答案 1 :(得分:2)

与编程中的大多数事情一样,有多种方法可以实现相同的结果 - 它主要归结为偏好。

这是我的解决方案。我个人觉得它更具可读性:

private _getTileContainer(): Observable<any> {

return Observable.interval(200)
    .map(_ => $('#googlemap').find('img[src*=\'kml\']')) // 1
    .take(30) // 2
    .skipWhile(tiles = tiles.length < 2) // 3
    .map(tiles => getContainer(tiles)) // 4
    .take(1); // 5
}
  1. 获取图片图块。
  2. 确保我们不要超过30次。
  3. 在我们至少有2个瓷砖之前发出的跳过信号。
  4. 拿到容器。
  5. 只需1个容器。

答案 2 :(得分:0)

这给了我我需要的东西,但我不确定是否有更好的方法

public updateTileContainer() {
  this._getTileContainer().subscribe(container => {

      console.log('* do stuff with container *');

  });
}


private _getTileContainer(): Observable<any> {

  return Observable.interval(200)
    .concatMap(n => {
      let tileContainer: any = null;

      const tileImages = $('#googlemap').find('img[src*=\'kml\']');         
      if (tileImages.length >= 2) {
        tileContainer = getContainer(tileImages);
      }

      return Observable.of(tileContainer);
    })
    .take(30)
    .filter(res => res !== null)
    .take(1);
}

因此,继原始示例之后,主Observable为前6或7次重​​试发出nulls,但filter()阻止它们传递给订阅者。 take(30)在30次重试后停止主Observable,而take(1)filter()在第一次非null 重试后停止Observable。

答案 3 :(得分:0)

  

在rxjs版本6.3.3上工作

    import { map, catchError, retryWhen, take, delay, concat } from 'rxjs/operators';
    import { throwError } from 'rxjs';


export class ApiEXT {

    static get apiURL(): string { return 'http://localhost:57886/api'; };
    static httpCLIENT: HttpClient;

 static POST(postOBJ: any, retryCOUNT: number = 0, retryITNERVAL: number = 1000) {
        return this.httpCLIENT
            .post(this.apiURL, JSON.stringify(postOBJ))
            .pipe(
                map(this.handleSUCCESS),
                retryWhen(errors => errors.pipe(delay(retryITNERVAL), take(retryCOUNT), concat(throwError("Giving up Retry.!")))),
                catchError(this.handleERROR));
    }


  private static handleSUCCESS(json_response: string): any {
        //TODO: cast_and_return    
        return JSON.parse(json_response);

    }

 private static handleERROR(error: Response) {
        let errorMSG: string;
        switch (error.status) {
            case -1: errorMSG = "(" + error.status + "/" + error.statusText + ")" + " Server Not Reachable.!"; break;
            default: errorMSG = "(" + error.status + "/" + error.statusText + ")" + " Unknown Error while connecting with server.!"; break;
        }
        console.error(errorMSG);
        return throwError(errorMSG);
    }

}

StackBlitz Example