RXJS Angular 5的管道操作符顺序

4

是我还是我的运算符顺序不正确?在下面的代码中,控制台日志中的两个水龙头返回相同的值。那肯定是不对的,对吧?

return this.pcs.getAvailableMaterials(currentProduct.id).pipe(
            map(
                result => result.result.data
            ),
            tap(
                x => console.log(x, 'before')
            ),
            map(
                materials => {
                    materials.forEach(material => {
                        material.type = 'material'
                    })
                    return materials
                }
            ),
            tap(
                x => console.log(x, 'after')
            ),
            tap(
                materials => {
                    setState({
                        ...state,
                        availableMaterials: materials
                    })
                }
            )
        )

使用NGXS开发的Angular 5应用程序。


this.pcs.getAvailableMaterials(currentProduct.id)的类型是什么?它是一个RXJS observable吗? - ethan.roday
你能否制作一个演示,展示一下结果与期望不符的情况? - martin
@err1100 是的,该函数返回一个可观察对象(HTTP 调用)。 - Dirk
1个回答

9
请注意,@samanime的答案不正确。请考虑对您原始代码进行以下修改:
return this.pcs.getAvailableMaterials(currentProduct.id).pipe(
        ...
        tap(
            x => console.log(x, 'before')
        ),
        map(
            materials => {
                materials.forEach(material => {
                    material.type = 'material'
                })
                return materials
            }
        ),
        delay(1000), // this line is new
        tap(
            x => console.log(x, 'after')
        ),
        ...
    )

您仍然可以将两个日志视为相同。对于@samanime的答案正确,console.log必须以某种方式需要花费一秒钟来执行,这显然不是事实。
问题在于RXJS期望管道函数是纯的。也就是说,没有任何管道函数应该创建任何在该函数执行之外持续存在的副作用。在您的第一个map调用中,您会改变materials数组内的对象,然后返回对相同数组的引用。这是一种副作用。要解决此问题,您应该从第一个map调用中返回一个新的数组。例如:
map(
  materials =>
    materials.map(material => { // map instead of forEach makes a new array
      return {...material, type: 'material'} // object spread makes new objects
    })
)

这应该能够给您预期的结果。

感谢 @err1100 编辑第二个映射表,问题解决了!所以不再需要使用 forEach,而是使用嵌套的映射表。 - Dirk
没错。在这种情况下它们“嵌套”的唯一原因是你的可观察对象首先发出数组(而不是单个值)。因此,外部的 map 将从可观察对象发出的每个数组转换为一些新数组,而内部的 map 是一个标准的 JS 数组 map,将每个发出的数组中的 转换为新的值。 - ethan.roday

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接