RxJs:在一个Observable <t>数组上的'Map',但是一旦T匹配条件就返回

时间:2016-07-22 14:00:27

标签: typescript angular rxjs

上下文:使用Angular2在TypeScript中编写的应用程序,+ rxjs 5.

编辑:我正在准备我对Rx库相对较新,以及应该采用“惯用方式”的方式。是的,在发布SO之前,我试图在文档中找到一些线索。

我有这个:

class Result { constructor(public inError: boolean) { } }

const checks : Array<() => Observable<Result>> = [...];

这是一个函数数组,每个函数返回一个包含Result对象的observable。

我想要的是什么:

  • 我想将此数组“映射”为Array<Observable<Result>>, 基本上是依次调用每个函数......
  • ...但是我想在第一个Result.inError成立时立即打破'地图'!

我被卡住了,摆弄reducetakeWithcontains等... Observables的延迟性质令我感到困惑。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

如果您的observable正在执行同步操作,您只需执行此操作:

const results = [];
for (const i = 0; i < checks.length; i +=1) {
    checks[i]().subscribe(result => if (result.inError) {
        break;
    } else {
        results.push(checks[i]());
    });
}
// Results observables accessible here.

在异步观察者案例中:

const results = [];
function callObservable(index) {
    checks[index]().subscribe(result => if (result.inError) {
            // Results observables accessible here.
        } else {
            results.push(checks[i]());
            callObservable(index + 1);
        })
}
callObservable(0);
但是,做任何这些都不会带来任何好处。您的observable在它们甚至到达结果数组之前已经被调用,或者如果再次从该数组调用,则会有另一个值。

答案 1 :(得分:0)

经过越来越多的挖掘,这是一个解决方案:

// Some class that will be contained in my observables
class Result { constructor(public inError: boolean) { } }

// An array of Observables that will emit those classes instances
// the thunk is just here to lazy instantiate the Result classes
// only when needed
const oResults : Array<() => Observable<Result>> = [
  Rx.Observable.of(() => new Result(false)),
  Rx.Observable.of(() => new Result(false)),
  Rx.Observable.of(() => new Result(true)),
  Rx.Observable.of(() => new Result(false))
];

// An home made (found on SO) INCLUSIVE 'takeWhile' version
const takeWhileInclusive(source, predicate){
    return source.publish(co => co.takeWhile(predicate)
        .merge(co.skipWhile(predicate).take(1)));
}

// Let's filter out things as expected
const res = takeWhileInclusive(
    Rx.Observable.merge(oResults).map( x => x()), 
    x => !x.inError
);

// I can now subscribe to the resulting stream and will only get
// all the first Results that are false AND the first following result that
// is true
res.subscribe(next => console.info("Next result", next));