Angular2路由和取消观察中流
我有一个Angular Http获取请求,将根据返回的数据将路线导航到三条路线之一。下面的示例代码:Angular2路由和取消观察中流
SomeComponent:
constructor(
private someService: SomeService,
private router: Router
) { }
ngOnInit() {
this.someService.getSomeData().subscribe(
() => {
console.log("getSomeData() did not route to a new link! Routing to a 3rd link");
this.router.navigate(['home']);
},
() => {
console.log("Some error occurred.");
});
SomeService:
constructor(
private router: Router,
private someOtherService: SomeOtherService
) { }
getSomeData() {
return this.someOtherService.getSomeOtherData().map(data => {
if (data === 'someValue') {
console.log("The data was 'someValue'");
this.router.navigate(['route1']);
}
else if (data == 'someOtherValue') {
console.log("The data was 'someOtherValue'");
this.router.navigate(['route2']);
}
});
}
SomeOtherService:
constructor(
private http: Http
) { }
getSomeOtherData() {
return this.http.get(this.getDataUrl) {
.map((res: Response) => {
console.log("Sending over the data back to SomeService");
let body = res.json();
return body.data;
})
.catch((err: Response) => {
console.log(err);
return Observable.throw(err);
});
}
}
预期的行为是从SomeOtherService接收数据后,路由器将导航到route1
或route2
取决于数据(我认为我在某处读取会停止Observable流?也许我误读了)。如果数据不匹配,则Observable流继续到SomeComponent,然后导航到home
。
实际的行为是,路由器最初将路由到route1
或route2
但由于流继续,路由器然后最终路由到home
。
所以我的问题是,如果您订阅rxjs Observable,是否有取消/取消订阅Observable中游的方法?我认为导航到另一条路线会取消可观察的,但这似乎不适用于我。
我试着用map
方法取消订阅,结果有趣(很差)。我也试过看其他Observable方法,但是对于rxjs来说是新手,我不确定哪种方法最合适(我在这一点上确实只熟悉map
,catch
,mapTo
和(sort of) switchMap
)。
预期的行为是在接收到数据后,来自SomeOtherService,路由器将根据数据导航到路由1或路由2(我认为我读过这些数据某处会阻止Observable流?也许我误读了)。如果数据不匹配,则Observable流继续到SomeComponent然后导航回家。
不太:-)
导航到另一个视图完成了由旧ActivatedRoute
提供的所有Observables
。您创建的Observables
不是从ActivatedRoute
(也不是通过其他方式绑定到ActivatedRoute
)获得的,因此将独立于哪条路由处于活动状态而存在。
此外,router.navigate(...)
是一个异步操作,这意味着它只调度导航,但不会等待导航完成。也就是说,即使您的Observables
与ActivatedRoute
绑定,他们仍然还活着,他们的观察员通知。
可以使用解决这个问题:
constructor(
private router: Router,
private someOtherService: SomeOtherService
) { }
getSomeData() {
return this.someOtherService.getSomeOtherData().map(data => {
if (data === 'someValue') {
console.log("The data was 'someValue'");
return ['route1'];
}
else if (data == 'someOtherValue') {
console.log("The data was 'someOtherValue'");
return ['route2'];
} else {
return null;
}
});
}
,并用它喜欢:
this.someService.getSomeData().subscribe({
next: (route) => {
this.router.navigate(route || ['home']);
},
error: (err) => {
console.log("Some error occurred.", err);
}
});
BTW,以更好地了解一个Observable
是什么,你可能想读ReactiveX documentation。
这解决了我试图实现的目标。但是为了让我清楚,是一个很好的总结,Observables只能发射值,只有Observer能够订阅/取消订阅Observables?因此Observable不能简单地停止向下游发送值,结束Observer(s)/ Observable的生命周期? – yoonjesung
Observable可能发送'next','completed'或'error'事件。 'completed'和'error'是终端事件。所以是的,一个'Observable'可能会拒绝向它的'Observers'发送更多的值。你的代码没有这样做,因为你使用了映射运算符,它发出映射函数的返回值(在你的情况下为'undefined')。您可以改为使用'flatMap'运算符,或者像Jagers的回答一样手动执行通知,但我发现我的解决方案更易于理解。 – meriton
有多种方式从可观察到的
最直接的方法是保持一个句柄订阅和取消例如在的OnDestroy方法退订。
import { Subscription } from 'rxjs/Rx'
...
private sub: Subscription;
constructor(
private someService: SomeService,
private router: Router
) { }
ngOnInit() {
this.sub = this.someService.getSomeData().subscribe(..)
}
ngOnDestroy() {
if (this.sub) this.sub.unsubscribe();
}
此外,在map()方法中进行导航有点奇怪。 map()运算符用于将可观察流转换为另一个流,它不是端点。所以通常你会返回类似someObs.map(s => s.name).subscribe()
。如果您只想执行某项操作,则可以使用do()
运算符。
但在你的情况下,如果数据==='someValue',你会先导航到map1运算符中的route1。然后订阅回调(next())被触发,路由器导航到'home'。
要得到的功能,你描述的,你可以做到这样:
SomeComponent:
constructor(
private someService: SomeService,
private router: Router
) { }
ngOnInit() {
this.someService.getSomeData().subscribe({
next:() => {
console.log("getSomeData() did not route to a new link! Routing to a 3rd link");
this.router.navigate(['home']);
},
complete:() => {},
error: (err) => {
console.log("Some error occurred.", err);
}
});
SomeService:
constructor(
private router: Router,
private someOtherService: SomeOtherService
) { }
getSomeData() {
return Observable.create(observer => {
this.someOtherService.getSomeOtherData().first().subscribe(data => {
if (data === 'someValue') {
console.log("The data was 'someValue'");
this.router.navigate(['route1']);
}
else if (data == 'someOtherValue') {
console.log("The data was 'someOtherValue'");
this.router.navigate(['route2']);
} else {
// none of the options above. call next() on the observer so
// it will route to 'home'
observer.next();
}
observer.complete();
});
});
}
使用observer的complete()方法作为可观察流的空停止的这种想法起作用。然而,我确定了评估者的答案是更好的,因为所有的路由最终都是由观察者自己处理的,观察者只是将必要的数据值发回给观察者。 – yoonjesung
如果你唯一的observable是由'this.http.get'生成的,那么当返回响应时这个observable会自动终止。无需取消它。 – DeborahK