Angular 如何从Observable.from收集发射值数组?

Angular 如何从Observable.from收集发射值数组?,angular,asynchronous,rxjs,reactive-programming,observable,Angular,Asynchronous,Rxjs,Reactive Programming,Observable,所以在Rxjs中,我有很多代码 return Observable.from(input_array) .concatMap((item)=>{ //this part emits an Observable.of<string> for each item in the input_array }) .scan((output_array:string[],each_item_ou

所以在Rxjs中,我有很多代码

return Observable.from(input_array)
           .concatMap((item)=>{
               //this part emits an Observable.of<string> for each item in the input_array
           })
           .scan((output_array:string[],each_item_output_array:string)=>{
               return output_array.push(each_item_output_array) ;
           });
return Observable.from(输入数组)
.concatMap((项目)=>{
//这部分为输入_数组中的每个项目发出一个可观察的.of
})
.scan((输出数组:字符串[],每个项目输出数组:字符串)=>{
返回输出\u数组.push(每个\u项\u输出\u数组);
});
但显然这是错误的,扫描将破坏concatMap中的代码,因此我想知道如何从操作符收集可观察的
中每个项目的输出数组?

在您对您的调用中,没有为累加器指定种子。在这种情况下,第一个值用作种子。例如:

Rx.Observable
.from([“a”、“b”、“c”])
.扫描((acc,值)=>acc+值)
.subscribe(值=>console.log(值))

另一个选项是
bufferCount(count)
如果您知道输入数组的长度,则可以获得包含该数量项的单个输出。比必须记住如何使用
scan
更简洁的语法

注意:如果您不知道大小(尽管在您的示例中您会知道),那么
count
表示一个最大值-但这可能有资源限制,所以不要仅将其设为99999

 const array = source$.pipe(bufferCount(10));
在我的例子中,我有一个正在执行的“操作”列表,并且我提前知道了步骤的总数,因此
bufferCount
工作得非常好。但是一定要仔细考虑错误条件

 // one approach to handling errors that still returns an output array
 // only use this if a single failure shouldn't stop the collection
 const array = source$.pipe(
                    map((result) => ({ hasError: false, result: result }),
                    catchError((err) => ({ hasError: true, error: err }),
                    bufferCount(10));
关于如何处理错误的决定将根据您的观察对象的实际情况而大不相同,但这里的要点是将
bufferCount()
显示为一个选项


(还有其他可用的
缓冲操作)

请小心此代码:

      const obs = Rx.Observable
      .from(["a", "b", "c"])
      .concatMap(value => Rx.Observable.of(value))
      .scan((acc, value) => {
        acc.push(value);
        return acc;
      }, []); 
      obs.subscribe(value => console.log(JSON.stringify(value)));
      obs.subscribe(value => console.log(JSON.stringify(value)));
结果将有点出乎意料:

 ["a"]
 ["a","b"]
 ["a","b","c"]
 ["a","b","c","a"]
 ["a","b","c","a","b"]
 ["a","b","c","a","b","c"]
 ["a"]
 ["a","b"]
 ["a","b","c"]
 ["a"]
 ["a","b"]
 ["a","b","c"]
“acc”变量是引用对象,每个订阅者获取流数据并再次向同一对象添加数据。 可能有很多解决方案可以避免,这是在再次接收流数据时创建新对象:

    var obs = Rx.Observable
          .from(["a", "b", "c"])
          .concatMap(value => Rx.Observable.of(value))
          .scan((acc, value) => {
          //clone initial value
            if (acc.length == 0) {

                   acc = [];
                }
            acc.push(value);
            return acc 
          }, []); // Note that an empty array is use as the seed
          obs.subscribe(value => console.log(JSON.stringify(value)));
          obs.subscribe(value => console.log(JSON.stringify(value)));
结果如预期:

 ["a"]
 ["a","b"]
 ["a","b","c"]
 ["a"]
 ["a","b"]
 ["a","b","c"]

我希望这能为某人节省很多时间

你说的“发线”是什么意思?传递给的
project
函数应该返回一个可观察的、承诺的或数组-不是字符串。@cartant,它是字符串的可观察的,它实际上是字符串,当然也是可观察的。事实上,我收回这一点-您可以返回字符串
concatMap
将对其进行迭代并发出其单个字符。如果我能将其向上投票100次,我会这样做。toArray解决了我一整天都在做的一个问题。非常感谢。您可以在每次迭代时返回一个新数组,而不是在第一个元素出现时创建一个新的空数组:
return[…acc,value]
。这是一种功能更强大的方法,浏览器在优化这方面做得很好。@sashee这是一个很好的观点,有很多解决方案,其主要思想是用数组打破对每个流数据的对象引用