【问题标题】:RXJS: Return the manipulated value of outer observableRXJS:返回外部 observable 的操作值
【发布时间】:2018-09-12 22:52:13
【问题描述】:

我试图调用两个 observable,第二个的响应我操纵第一个,然后返回一个新的 observable。

return this.http.get(requestUrl)
            .map((response: User) => {
                sessionManager.currentUser = response;
                return this.isFirstTimeUser(response.id);
            })
            .do((response: any) => {
                console.log(response);
                sessionManager.currentUser.firstTimeLogin = response === 'true';
                return Observable.create(sessionManager.currentUser);
            })
            .toPromise();

isFirstTimeUser(response.id) 是另一个返回 observable 的函数。

private isFirstTimeUser(userId: number): Observable<any> {
        const requestUrl = 'someUrl';
        return this.http.get(requestUrl, {responseType: 'text'});
    }

我想要做的就是从第一个 http 调用中获取用户对象,在第二个调用中使用用户的 id 发出另一个请求,然后在我从第二个 observable 得到响应后,我更新了一个属性第一个响应并返回更新后的第一个响应。我如何实现这一目标?我应该看什么 rxjs 函数?

【问题讨论】:

  • 在你的例子中,你在哪里调用第二个 observable?
  • isFirstTimeUser(response.id) 返回另一个 http Observable。
  • 查看我的更新答案
  • 你能更好地解释你想要做什么吗?我试图想出答案,但你的描述不清楚。
  • @codeepic 编辑有帮助吗?

标签: angular typescript rxjs httpclient


【解决方案1】:

您正在寻找的解决方案是这样的:

getUser(): Observable<any>{
    return this.http.get(reqUrl)
        .do((res: User) => {
            sessionManager.currentUser = res;
        })
        .switchMap((res: User) => {
            return this.isFirstTimeUser(res.id);
        })
        .do((res: any) => {
            console.log(response);
        }
        .map((res: any) => {
            sessionManager.currentUser.firstTimeLogin = res === 'true';
            return sessionManager.currentUser;
        });
}

那么你只需要订阅getUser() 就可以了。根据纯函数的 rxjs 函数范式,它仍然不是最好的代码。我想使用带有投影功能的concatMap 会让我们更接近理想,但它会起作用。

它不理想的原因是因为在第一个 .do() 块中有一个必需的副作用,我们更新了 sessionManager 值 - 函数外部的变量(函数世界中的一个大禁忌)然后我们访问它再次在.map() 函数中。 concatMap 将投影函数作为第二个参数将帮助我们解决这个问题。

【讨论】:

    【解决方案2】:

    你的例子很接近。

    您想使用switchMap,它取消订阅传入的可观察对象,并订阅下一个可观察对象。

    return this.http.get(requestUrl)
            .switchMap((response: User) => {
                sessionManager.currentUser = response;
                return this.isFirstTimeUser(response.id);
            })
            .map((response: any) => {
                console.log(response);
                sessionManager.currentUser.firstTimeLogin = response === 'true';
                return sessionManager.currentUser;
            })
            .toPromise();
    

    响应将被传递给isFirstTimeuser(),随后.map() 将应用于该函数返回的可观察对象。

    之所以称为switchMap,是因为this.http.get() 返回的可观察对象已取消订阅,并且使用了下一个可观察对象。这不会是this.http.get() 的问题,但请记住switchMap 仅适用于第一个 发出的值。

    【讨论】:

    • 这太美了!非常感谢!
    【解决方案3】:

    使用mergeMap

    return this.http.get(requestUrl)
                .mergeMap((response: User) => {
                    const currentUser = response;
                    currentUser.firstTimeLogin = this.isFirstTimeUser(response.id) === 'true' 
                    return Observable.of(currentUser);
                })
    

    【讨论】:

    • 你的例子我不清楚,所以我用了这个
    • 这不是我的例子。这是我的问题。我正在为我的特定问题寻找解决方案,因为我不太精通 rxjs。你认为你可以编辑答案来解决我的问题吗?
    • 在 rxjs 中你不应该修改除了可观察的发射之外的任何变量,在这里你改变 sessionManager,这在 RX 的上下文中是无效的
    • 这是真的,如果你这样做sessionManager.currentUser = response 这是一个不好的做法。因为它是可观察流之外的副作用。
    • this.isFirstTimeUser(response.id) === 'true' 永远不会是真的。它返回一个可观察的。请参阅 OPs cmets。
    猜你喜欢
    • 2021-12-20
    • 2019-08-05
    • 2020-05-22
    • 2017-12-28
    • 2016-12-18
    • 1970-01-01
    • 2018-08-07
    • 2018-12-16
    • 1970-01-01
    相关资源
    最近更新 更多