什么rxjs运算符就像concatmap,但在触发下一个请求之前等待每个请求?

时间:2017-07-11 11:51:09

标签: angular rxjs rxjs5

例如,假设我想做一些api调用。我正在处理的api容易出现竞争条件,所以如果我同时在服务器上更新同一条数据进行3次api调用,它可能会丢失部分数据。

因此,我想排队我的请求,然后在解除下一个请求之前等待响应返回。

基本上我需要类似concatMap的东西,但concatMap的问题是它同时触发所有请求。我需要concatMap才能在开始下一个请求之前等待。我正在使用rxjs 5。

这是一个使用angular2的plunker,你可以点击按钮。单击1秒按钮时,将创建一个在1秒后返回的observable。有2秒和3秒的按钮。

https://plnkr.co/edit/6F4JrVueQX8PjPinZqIk?p=preview

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Wait:</h2>

      <button (click)="start(1)">1 sec</button>
      <button (click)="start(2)">2 sec</button>
      <button (click)="start(3)">3 sec</button>
    </div>
  `,
})
export class App {


  constructor() {
  }

  start(wait) {

    const waitSecs = parseInt(wait) * 1000;

    of('clicked').delay(waitSecs).subscribe(
      val => console.log(wait)  
    )

    // Expected behavior:
    // I click 3 sec, 2 sec, and 1 sec right after another.  Then 
    // the console log should output 3, 2, 1.  Right now it's 
    // outputting 1, 2, 3.

  }
}

我使用此应用程序的理想行为是在我依次点击3秒,2秒​​和1秒之后。然后控制台应该输出3,2,1。现在它是 输出1,2,3。

2 个答案:

答案 0 :(得分:3)

你应该发布一些代码。 concatMap应该适用于您的用例。如果您在订阅之前观察到触发,则意味着您需要使用defer运算符在订阅时进行触发但没有代码示例则很难说更多。

过去问题的有用链接:

答案 1 :(得分:3)

由于您只想执行请求,因此您可以使用mergeMap()运算符并将concurrency设置为1.请注意,这将意味着待发送项目将在mergeMap内排队可能导致内存问题的运算符。

Rx.Observable.from([3,5,2,1])
  .mergeMap(
    i => {
      return Rx.Observable.of(i)
        .do(i => console.log(`starting request for ${i}`))
        .delay(1000)
        .do(null,null, () => console.log(`finished request for ${i}`));
    },
    null,
    1 /* concurrency limited to 1 */
  )
  .subscribe(val => console.log(`received value: ${val}`));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.2/Rx.js"></script>