[英]RXJS Wait for all observables in an array to complete (or error)
我正在将 observables 推入这样的数组中......
var tasks$ = [];
tasks$.push(Observable.timer(1000));
tasks$.push(Observable.timer(3000));
tasks$.push(Observable.timer(10000));
我想要一个 Observable 在所有任务 $ 完成时发出。 请记住,在实践中,tasks$ 没有已知数量的 Observable。
我试过Observable.zip(tasks$).subscribe()
但这似乎在只有 1 个任务的情况下失败,并且让我相信 ZIP 需要偶数个元素才能工作我会期待。
我试过Observable.concat(tasks$).subscribe()
但 concat 运算符的结果似乎只是一个可观察的数组......例如,与输入基本相同。 你甚至不能打电话订阅它。
在 C# 中,这类似于Task.WhenAll()
。 在 ES6 promise 中,它类似于Promise.all()
。
我遇到了许多 SO 问题,但它们似乎都在处理等待已知数量的流(例如将它们映射在一起)。
如果您想forkJoin
一个在所有源 observable 完成时发出的 observable,您可以使用forkJoin
:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';
import 'rxjs/add/operator/first';
var tasks$ = [];
tasks$.push(Observable.timer(1000).first());
tasks$.push(Observable.timer(3000).first());
tasks$.push(Observable.timer(10000).first());
Observable.forkJoin(...tasks$).subscribe(results => { console.log(results); });
您可以使用zip
。
组合多个 Observable 以创建一个 Observable,其值是根据每个输入 Observable 的值按顺序计算的。
const obsvA = this._service.getObjA();
const obsvB = this._service.getObjB();
// or with array
// const obsvArray = [obsvA, obsvB];
const zip = Observable.zip(obsvA, obsvB);
// or with array
// const zip = Observable.zip(...obsvArray);
zip.subscribe(
result => console.log(result), // result is an array with the responses [respA, respB]
);
需要考虑的事项:
zip
正如这里所说,
zip 操作符将订阅所有内部 observable,等待每个都发出一个值。 一旦发生这种情况,将发出具有相应索引的所有值。 这将一直持续到至少一个内部 observable 完成。
onComplete
on complete 被调用),并且使用onError
方法,您只会得到第一个错误。zip.subscribe(
result => console.log(result), // result is an array with the responses [respA, respB]
error => console.log(error), // will return the error message of the first observable that throws error and then finish it
() => console.log ('completed after first error or if first observable finishes)
);
// waits for all Observables no matter of success/fails each of them
// returns array of items
// each item represent even first value of Observable or it's error
export function waitAll(args: Observable<any>[]): Observable<any[]> {
const final = new Subject<any[]>();
const flags = new Array(args.length);
const result = new Array(args.length);
let total = args.length;
for (let i = 0; i < args.length; i++) {
flags[i] = false;
args[i].subscribe(
res => {
console.info('waitAll ' + i + ' ok ', res);
if (flags[i] === false) {
flags[i] = true;
result[i] = res;
total--;
if (total < 1) {
final.next(result);
}
}
},
error => {
console.error('waitAll ' + i + ' failed ', error);
if (flags[i] === false) {
flags[i] = true;
result[i] = error;
total--;
if (total < 1) {
final.next(result);
}
}
}
);
}
return final.asObservable();
}
单元测试:
describe('waitAll', () => {
it('should wait for all observables', async () => {
const o1 = new Subject();
const o2 = new Subject();
const o3 = new Subject();
const o = waitAll([o1, o2, o3]);
const res = {arr: []};
o.subscribe(result => res.arr = result, err => res.arr = []);
expect(res.arr).toEqual([]);
o1.next('success1');
expect(res.arr).toEqual([]);
o2.error('failed2')
expect(res.arr).toEqual([]);
o3.next('success3')
expect(res.arr).toEqual(['success1', 'failed2', 'success3']);
o1.next('success1*');
expect(res.arr).toEqual(['success1', 'failed2', 'success3']);
o2.error('failed2*')
expect(res.arr).toEqual(['success1', 'failed2', 'success3']);
o3.next('success3*')
expect(res.arr).toEqual(['success1', 'failed2', 'success3']);
});
});
对我来说,这个 样本是最好的解决方案。
const source = Observable.interval(500);
const example = source.sample(Observable.interval(2000));
const subscribe = example.subscribe(val => console.log('sample', val));
所以..只有当第二个(示例)发出时 - 你会看到第一个(源)的最后发出的值。
在我的任务中,我等待表单验证和其他 DOM 事件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.