rxjs中如何做链序
Posted
技术标签:
【中文标题】rxjs中如何做链序【英文标题】:How to do the chain sequence in rxjs 【发布时间】:2016-10-11 10:07:17 【问题描述】:我想这样做:
this._myService.doSomething().subscribe(result =>
doSomething()
);
.then( () => dosthelse() )
.then( () => dosanotherthing() )
所以我想在承诺中链接 .then。我将如何在 Rxjs 中做到这一点?
this._myService.getLoginScreen().subscribe( result =>
window.location.href = MyService.LOGIN_URL;
/// I would like to wait for the site to load and alert something from the url, when I do it here it alerts the old one
);
.then (alert(anotherService.partOfTheUrl())
getLoginScreen()
return this.http.get(myService.LOGIN_URL)
.flatMap(result => this.changeBrowserUrl())
.subscribe( result => //i want to do sth when the page is loaded//);
changeBrowserUrl(): Observable<any>
return Observable.create( observer =>
window.location.href = myService.LOGIN_URL;
observer.next();
);
【问题讨论】:
Chaining RxJs Observables in Angular 2的可能重复 注意你的类型!!.subscribe
返回 Disposable
而不是 Observable
【参考方案1】:
对于 observables,then
的等价物是 flatMap
。您可以在此处查看一些使用示例:
对于您的示例,您可以执行以下操作:
this._myService.doSomething()
.flatMap(function(x)return functionReturningObservableOrPromise(x))
.flatMap(...ad infinitum)
.subscribe(...final processing)
注意你的函数返回的类型,因为使用flatMap
链接observables 你需要返回一个promise 或一个observable。
【讨论】:
我不知道我会说 flatMap 与 then 是等价的。 flatMap 实际上是对数据进行操作。 reactivex.io/documentation/operators/flatmap.html 如果我们不想要第 n 个 observable 的结果,而是想要没有转换的原始事件怎么办? 有没有办法停止下一个链式方法,以防上一个失败?【参考方案2】:如果dosthelse
或dosanotherthing
返回原始值,则要使用的运算符是map
。如果它是可观察的,则运算符为 flatMap
(或等效项)。
如果你想强制地做某事。我的意思是在异步处理链之外,您可以利用 do
运算符。
假设 dosthelse
返回一个可观察对象,dosanotherthing
返回一个原始对象,您的代码将是:
this._myService.doSomething()
.do(result =>
doSomething();
)
.flatMap( () => dosthelse() )
.map( () => dosanotherthing() );
注意,如果你返回订阅方法的返回值,它将对应一个订阅对象,而不是一个可观察对象。订阅对象主要是为了能够取消observable,不能参与异步处理链。
事实上,大多数时候,你是在链的末端订阅的。
所以我会这样重构你的代码:
this._myService.getLoginScreen().subscribe( result =>
window.location.href = MyService.LOGIN_URL;
/// I would like to wait for the site to load and alert something from the url, when I do it here it alerts the old one
alert(anotherService.partOfTheUrl()
);
getLoginScreen()
return this.http.get(myService.LOGIN_URL)
.flatMap(result => this.changeBrowserUrl())
.do( result => //i want to do sth when the page is loaded//);
changeBrowserUrl(): Observable<any>
return Observable.create( observer =>
window.location.href = myService.LOGIN_URL;
observer.next();
);
【讨论】:
RxJS API 已更改,请参阅此处了解如何使用 Angular 5+ 执行 flatMap:***.com/a/47841977/2506594 从 RxJS v6+ 开始,在pipe
中使用 tap
运算符而不是 do
。【参考方案3】:
更新 rxjs 解决方案
自从回答这个问题后,Rxjs 发生了很大变化。
flatMap
现在是 mergeMap
或switchMap
,它们大多可以互换,但很高兴知道它们的区别
.do()
现在是 tap()
链接现在在.pipe()
内完成。所有操作都应在此管道内完成
如果需要,您可以链接管道(例如,一个变量映射一组用户。另一个变量获取第一个变量并再次映射它)
在最初的调用之后做一些事情
场景
进行 HTTP 调用(例如身份验证检查) 通话结束后,导航到另一个页面this._myService.getAuthenticated()
.pipe(
tap(result => this._myService.navigateToHome())
)
.subscribe()
链接多个调用
场景
进行 HTTP 调用(例如身份验证检查) 拨打第二个电话以获取更多信息 两个通话结束后导航this._myService.getAuthenticated()
.pipe(
// The Authentication call returns an object with the User Id
switchMap(user => this._myService.getUserInfo(user.id))
// After the user has been loaded, navigate
tap(user => this._myService.navigateToHome())
)
.subscribe()
关于上述示例的注意事项:我假设这些调用是 HTTP,在调用一次后取消订阅。如果您使用实时 observable(例如用户流),请确保您取消订阅或使用 takeUntil/first
运算符。
【讨论】:
以上是关于rxjs中如何做链序的主要内容,如果未能解决你的问题,请参考以下文章
如何在不需要 rxjs-compat 的情况下只导入 RxJS 6 中使用的运算符,如旧的 RxJS?