如何在RxJS Observable流后续步骤中使用响应属性?
你发送请求后得到的响应包含body和cookies两个属性,结构如下:
{body:[row1,...,rowN], cookies:sessionData}
现在你的RxJS代码流程里,第一个map操作(标记为(1))解析了响应的body,但到后面的map(标记为(2))时,因为作用域问题已经拿不到最初的res对象了。你想知道有没有RxJS专属的方法能在后续步骤获取cookies,还是必须在第一个map里就把cookies合并到流数据中?
当前代码示例:
this.sendRequest("find",params) .map((res:Library.Response) => JSON.parse(res.body)) // (1) 解析响应body .map((data) => this.filterFindings(data)) // 过滤有效数据 .map((data) => this.addCookies(data, res.cookies)) // (2) 想要添加res的cookies,但res已无法访问
解决方案
其实RxJS里有几种实用的方法可以解决这个问题,不一定非要在第一个map就把cookies塞进去,下面分享两种最常用的思路:
方法1:在初始操作中保留完整上下文(推荐)
最简单直接的方式,就是在第一个map里不要只返回解析后的body,而是把body和cookies打包成一个对象,让后续所有操作符都能拿到完整的数据:
this.sendRequest("find", params) .map((res: Library.Response) => ({ rawData: JSON.parse(res.body), sessionCookies: res.cookies })) // 把需要的所有上下文数据都保留在流中 .map(({ rawData, sessionCookies }) => ({ filteredData: this.filterFindings(rawData), sessionCookies })) // 过滤后依然携带cookies .map(({ filteredData, sessionCookies }) => this.addCookies(filteredData, sessionCookies))
这种方式逻辑清晰,可读性强,也是RxJS里处理上下文传递最常用的方案,不容易出现作用域相关的问题。
方法2:用switchMap/concatMap通过闭包保留上下文(适合复杂场景)
如果你的后续流程包含异步操作,或者不想一直传递复合对象,也可以用switchMap(或concatMap)创建嵌套流,利用闭包特性保留初始的res对象:
this.sendRequest("find", params) .switchMap((res: Library.Response) => { const parsedData = JSON.parse(res.body); const filteredData = this.filterFindings(parsedData); // 这里可以直接访问res.cookies,因为闭包保留了这个变量的引用 return Rx.Observable.of(this.addCookies(filteredData, res.cookies)); })
不过如果只是纯同步操作的话,第一种方法会更简洁直观。
有没有RxJS专属的特殊操作符?
其实并没有专门为这种场景设计的“魔法”操作符,因为RxJS的流是单向数据流,每个操作符只处理当前流中的值。所以核心思路只有两个:要么把需要的上下文数据一直携带在流的 payload 里,要么通过闭包保留住上下文变量。
总结一下:简单同步流程选方法1,复杂异步嵌套场景选方法2,两种方案都能完美解决你的问题。
内容的提问来源于stack exchange,提问作者fastr.de
相关产品推荐
相关产品推荐

