如何将每个内部可观测值(RxJs)与外部相结合并发出一个数组?

时间:2020-06-17 20:52:03

标签: angular rxjs expand

当我触发此代码时:

timer(1000).pipe(
  expand(() => of('a')),
  take(3)
)
  .subscribe(data => alert(data));

我收到3次警报:警报为0,警报为“ a”,警报为“ a”。 我只想通过数组[0,a,a]收到一个警报。 如何合并所有值?

2 个答案:

答案 0 :(得分:2)

您的问题很有趣,并且(如Michael D在其回答中所述)非常具体的用例。

An example of the following code, working in StackBlitz

我建议您使用reduce,而不是使用scan(这将为您提供3种排放量中每个排放量上的当前累积值),webchat只会在来源完成。

import { of, timer } from 'rxjs';
import { reduce, expand, take } from 'rxjs/operators';

timer(1000).pipe(
  expand(() => of('a')),
  take(3),
  reduce((acc, val) => { acc.push(val); return acc; }, [])
).subscribe(val => console.log('Output:', val));

//输出:[0,a,a]

答案 1 :(得分:1)

这看起来是一个非常具体的用例,并且有多种实现方法。

选项1:scanfilter运算符

timer(1000).pipe(
  expand(() => of('a')),
  take(3),
  scan((acc, curr) => {
    acc.push(curr);    // <-- push each notification to the array
    return acc;        
  }, []),              // <-- empty array `[]` as seed value 
  filter(values => values.length === 3)    // <-- emit only if notification length is 3
).subscribe(data => alert(data));

请注意,使用scan的可观察符正在发出3条通知:[0][0, 'a'][0, 'a', 'a']。我们明确限制仅发出最后一个通知,因为我们知道它的长度应为3(由于take(3))。

选项2:scantakeLast运算符

timer(1000).pipe(
  expand(() => of('a')),
  take(3),
  scan((acc, curr) => {
    acc.push(curr);    // <-- push each notification to the array
    return acc;        
  }, []),              // <-- empty array `[]` as seed value 
  takeLast(1)          // <-- emit the last 1 notification
).subscribe(data => alert(data));

选项3:scanlast运算符

timer(1000).pipe(
  expand(() => of('a')),
  take(3),
  scan((acc, curr) => {
    acc.push(curr);    // <-- push each notification to the array
    return acc;        
  }, []),              // <-- empty array `[]` as seed value 
  last()               // <-- emit the last notification
).subscribe(data => alert(data));

last运算符还提供了一个类似于filter运算符的选项。您可以传递谓词,并且仅在满足谓词的情况下才会发出通知。

timer(1000).pipe(
  expand(() => of('a')),
  take(3),
  scan((acc, curr) => {
    acc.push(curr);    // <-- push each notification to the array
    return acc;        
  }, []),              // <-- empty array `[]` as seed value 
  last((values) => values.includes('a'))     // <-- emit only if array contains 'a'
).subscribe(data => alert(data));

选项4:reduce运算符

请参阅@NathanBeck的answer

更新

选项5:toArray运算符

可能最快的解决方案是使用toArray()运算符。

timer(1000).pipe(
  expand(() => of('a')),
  take(3),
  toArray()
).subscribe(data => alert(data));