如何使用angular2

时间:2017-02-15 21:21:13

标签: rest angular angular-services

我的API限制为每秒10次调用(但每天数千次),但是,当我运行此函数时(称为对象的每个样式ID,>每秒10次):

  getStyleByID(styleID: number): void {
    this._EdmundsAPIService.getStyleByID(styleID).subscribe(
      style => {this.style.push(style); },
      error =>  this.errorMessage = <any>error);
  }

来自这个函数(只有1个调用,使用onInit):

  getStylesWithoutYear(): void {
    this._EdmundsAPIService.getStylesWithoutYear(this.makeNiceName, this.modelNiceName, this.modelCategory)
      .subscribe(
        styles => { this.styles = styles;
                      this.styles.years.forEach(year =>
                        year.styles.forEach(style =>
                          this.getStyleByID(style.id)));

        console.log(this.styles); },
        error =>  this.errorMessage = <any>error);
  }

它使&gt; 10次​​拨打电话。如何阻止或减慢这些调用以防止出现403错误?

3 个答案:

答案 0 :(得分:2)

您可以使用每n毫秒触发一次的定时Observable。我没有调整你的代码,但是这个代码显示了它的工作方式:

someMethod() {
  // flatten your styles into an array:
  let stylesArray = ["style1", "style2", "style3"];

  // create a scheduled Observable that triggers each second
  let source = Observable.timer(1000,1000);
  // use a counter to track when all styles are processed
  let counter = 0;

  let  subscription = source.subscribe( x => {
    if (counter < stylesArray.length) {
        // call your API here
        counter++;
    } else {
        subscription.complete();
    }
  });
}

在此处找到plunk,其中显示了它的实际效果

答案 1 :(得分:2)

我有一个非常巧妙的解决方案,你将两个observables .zip() operator结合起来:

  1. 发出请求的观察者。
  2. 另一个观察者每隔0.1秒发出一个值。
  3. 您最终每隔<.1秒发出一次可观察的发出请求(=每秒10次请求)。

    以下是代码(JSBin):

    // Stream of style ids you need to request (this will be throttled).
    const styleIdsObs = new Rx.Subject<number>();
    
    // Getting a style means pushing a new styleId to the stream of style ids.
    const getStyleByID = (id) => styleIdsObs.next(id);
    
    // This second observable will act as the "throttler".
    // It emits one value every .1 second, so 10 values per second.
    const intervalObs = Rx.Observable.interval(100);
    
    Rx.Observable
      // Combine the 2 observables. The obs now emits a styleId every .1s. 
      .zip(styleIdsObs, intervalObs, (styleId, i) => styleId)
      // Get the style, i.e. run the request.
      .mergeMap(styleId => this._EdmundsAPIService.getStyleByID(styleId))
      // Use the style.
      .subscribe(style => {
        console.log(style);
        this.style.push(style);
      });
    
    // Launch of bunch of requests at once, they'll be throttled automatically.
    for (let i=0; i<20; i++) {
      getStyleByID(i);
    }
    

    希望您能够将我的代码翻译成您自己的用例。如果您有任何问题,请告诉我。

    更新:感谢Adam,还有一个JSBin显示如果请求不一致,请如何限制请求(请参阅评论中的convo)。它使用concatMap()运算符代替zip()运算符。

答案 2 :(得分:1)

虽然我没有测试这段代码,但我会尝试这些代码。

基本上我创建了一个变量,用于跟踪何时允许进行下一个请求。如果该时间尚未过去,并且有新请求进入,则将使用setTimeout允许该函数以适当的时间间隔运行。如果delayUntil值是过去的,那么请求可以立即运行,并且还可以将计时器从当前时间推回100毫秒。

delayUntil = Date.now();

getStylesWithoutYear(): void {
  this.delayRequest(() => {
    this._EdmundsAPIService.getStylesWithoutYear(this.makeNiceName, this.modelNiceName, this.modelCategory)
      .subscribe(
        styles => { this.styles = styles;
                    this.styles.years.forEach(year =>
                      year.styles.forEach(style =>
                        this.getStyleByID(style.id)));

        console.log(this.styles); },
        error =>  this.errorMessage = <any>error);
  };        
}

delayRequest(delayedFunction) {
  if (this.delayUntil > Date.now()) {
    setTimeout(delayedFunction, this.delayUntil - Date.now());
    this.delayUntil += 100;
  } else {
    delayedFunction();
    this.delayUntil = Date.now() + 100;
  }
}