同步多个异步结果

时间:2018-04-10 14:54:11

标签: angular typescript

我有一个角度应用程序,它使用一个服务来填充一个数组以在表中使用,但结果需要第二次转换才能准备好呈现。我正在调用另一个服务,但是在我提醒用户界面完成之前我怎么知道我完全完成所有转换?我试过这个(天真的方法),但它有一个缺陷:

this.dataService.getData().subscribe(result => {
  result['entries'].forEach(entry => {
    let fieldToTransform = entry['fieldToTransform'];
    this.transformService.transform(fieldToTransform).subscribe(transformedField => {
      entry['fieldToTransform'] = transformedField;
    });// hmm, can't alert UI here
  });// not here either
});

但很明显,循环的每次迭代都会调用服务并在不同时间完成。我怎么知道它们何时完成?

2 个答案:

答案 0 :(得分:1)

如果可以提供帮助,请避免多次订阅。在这种情况下,我认为你可以。

我希望这个例子有意义。有许多方法/操作员可以实现您需要的变化。我在下面的示例中使用了concatMap()toArray()map()。此示例假定您的第二个异步服务调用始终返回1个值。

// simulates first async service call
const sourceOne = Rx.Observable.of(1,2,3);
// simulates second async service call
const sourceTwo = Rx.Observable.of('something-from-two');

// for each value from source one, process it after getting a value from source two
const example = sourceOne.concatMap(sourceOneValue => {
  return sourceTwo.map(sourceTwoValue => '---' + sourceOneValue + ':' + sourceTwoValue + '---')
})

// as separate values
example.subscribe(val => console.log(val));
// as a single array
// example.toArray().subscribe(val => console.log(val));

请参阅此runnable example并进行调整以满足您的需求。

这实际上是关于RxJS的问题,如果示例不充分,我建议进一步阅读该主题以满足您的特定用例。

答案 1 :(得分:0)

在您的第二个嵌套Observable订阅中,您可以获得两次通话的结果。

this.dataService.getData().subscribe(result => {
  result['entries'].forEach(entry => {
    let fieldToTransform = entry['fieldToTransform'];
    this.transformService.transform(fieldToTransform).subscribe(transformedField => {
      entry['fieldToTransform'] = transformedField;
      // <<< --- maybe here? you have results from both of your service methods
    });// hmm, can't alert UI here
  });// not here either
});

编辑:

那么你应该使用某种合并的Observable运算符。

http://reactivex.io/documentation/operators.html @ Combining Observables

这是一个例子(我现在无法验证它,但也许它可以帮助你一个想法):

this.dataService.getData().subscribe(result => {
  let transformSubscriptions = [];

  result['entries'].forEach(entry => {

    let fieldToTransform = entry['fieldToTransform'];

    const sub = this.transformService.transform(fieldToTransform)
      .do(transformedField => {
        entry['fieldToTransform'] = transformedField;
      })

    transformSubscriptions.push(sub);
  });

  Observable.combineLatest(transformSubscriptions)
    .subscribe(results => window.alert('All transfers happened (at least once)'));
});