4

JSBIN 示例

我有一组可变的子组件(POJO 对象),每个子组件都有自己的状态流。每次用户触发 addChild/removeChild/clearChildren 时,都会使用#switchMap 发出一组新的子状态流。到现在为止还挺好!(对 RxJS 感到非常惊讶!)

只要不是空数组Rx.Observable.from(arrayOfStateStreams).combineAll(),我就会得到一个很好的结果。arrayOfStateStreams

由于这是在更高级别上组合(最新)的部分状态,因此我需要发出一个空数组,否则全局状态树将包含不再正确的旧状态数据!

我可以发出一些保留的令牌,例如['EMPTY-ARRAY-PLACEHOLDER-TOKEN'],但这很奇怪。更好的方法是始终将最后一个流附加到数组中,以便可以将最后一个索引视为垃圾。尽管如此,代码和状态仍然令人困惑。使用[null]是不行的,因为我们可以有一个'null'.

任何人都可以很好地解决这个问题?由于在#combineAll 之后不应该有其他空数组表示,因此不能支持这一点吗?

4

4 回答 4

3

致谢github 用户 trxcllnt 提供了以下答案

除非组合的 Observable 发出至少一个值,否则 combineAll 不会发出,但您可以检查以确保您正在组合的集合是否为空,然后组合或发出一个空数组:

 var arrayOfStreamsStream = Rx.Observable
    .of(
        [], [
            Rx.Observable.of('blah-1'), // component state.
            Rx.Observable.of('blah-2'),
            Rx.Observable.of('blah-3')
        ], [], [
            Rx.Observable.of('foo-1'),
            Rx.Observable.of('qux-2')
        ]
    )
    .switchMap(function onMap(coll) {
        return coll.length === 0 ?
            Observable.of(coll) :
            Observable.combineLatest(...coll);
    })
    .subscribe(function onSubscribe(data) {
        console.log('onSubscribe START')
        console.dir(data)
        console.log('onSubscribe END')
    }) 
于 2016-09-01T08:27:16.673 回答
2

这与combineAll. 问题是Observable.from当传递一个空数组时什么都没有(一个空的 observable)。

如果您必须从空数组中获取结果,我能想到的唯一可行的解​​决方案是在这种情况下返回其他内容。

一个例子来说明问题和可能的解决方案。

var data = [1, 2, 3, 4, 5];

log('With data: ');
Rx.Observable.from(data)
    .subscribe(function (d) { log('data: ' + d); });

// Prints: 
// With data: 
// data: 1
// data: 2
// data: 3
// data: 4
// data: 5

var data = [];

log('Without data: ');
var nullDataObject = { msg: 'my null data object' };
Rx.Observable.from(data.length == 0 ? [nullDataObject] : data)
    .subscribe(function (d) { log('data: ' + d); });

// Prints: 
// With data: 
// data: [object Object]

jsfiddle上的可运​​行示例。

使用它时,您只需在适当的地方过滤掉表示空数组的对象。

于 2016-08-31T07:33:08.597 回答
0

一种可能的解决方法是使用 startWith() 进行管道传输;

combineLatest(potentiallyEmptyArray).pipe(
    startWith<any>([])
);
于 2021-09-02T13:31:27.743 回答
0

注意:(静态版本)存在类似问题combineLatest(),可以使用defaultIfEmpty()- 解决,但它会破坏输出的类型。

// array of Observables
const animals: Observable<{ species: 'dog' | 'cat' }>[] = [];  

// Type '{ species: "dog" | "cat"; }[]' is not assignable to type 'never[]'.
combineLatest(animals).pipe(defaultIfEmpty([]));  

在 TypeScript 中,您需要知道对象的类型或使用<any>[],这意味着您将完全失去输入。

如果您有具体类型,则可以使用以下其中一种:

defaultIfEmpty<Animal[]>([])

defaultIfEmpty([] as Animal[])

对于可观察对象的返回值,我经常没有具体的类型。所以我想出了一个操作员:

 export const emptyArrayIfEmpty = () => <T>(observable: Observable<T[]>) =>
                                        observable.pipe(defaultIfEmpty([] as T[]));

animals === []然后我可以添加以下内容并在不丢失任何输入信息的情况下取出一个空数组:

combineLatest(animals).pipe(emptyArrayIfEmpty());  
于 2021-11-28T05:20:06.853 回答