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接收数据后,路由器将导航到route1route2取决于数据(我认为我在某处读取会停止Observable流?也许我误读了)。如果数据不匹配,则Observable流继续到SomeComponent,然后导航到home

实际的行为是,路由器最初将路由到route1route2但由于流继续,路由器然后最终路由到home

所以我的问题是,如果您订阅rxjs Observable,是否有取消/取消订阅Observable中游的方法?我认为导航到另一条路线会取消可观察的,但这似乎不适用于我。

我试着用map方法取消订阅,结果有趣(很差)。我也试过看其他Observable方法,但是对于rxjs来说是新手,我不确定哪种方法最合适(我在这一点上确实只熟悉map,catch,mapTo(sort of) switchMap)。

+0

如果你唯一的observable是由'this.http.get'生成的,那么当返回响应时这个observable会自动终止。无需取消它。 – DeborahK

预期的行为是在接收到数据后,来自SomeOtherService,路由器将根据数据导航到路由1或路由2(我认为我读过这些数据某处会阻止Observable流?也许我误读了)。如果数据不匹配,则Observable流继续到SomeComponent然后导航回家。

不太:-)

导航到另一个视图完成了由旧ActivatedRoute提供的所有Observables。您创建的Observables不是从ActivatedRoute(也不是通过其他方式绑定到ActivatedRoute)获得的,因此将独立于哪条路由处于活动状态而存在。

此外,router.navigate(...)是一个异步操作,这意味着它只调度导航,但不会等待导航完成。也就是说,即使您的ObservablesActivatedRoute绑定,他们仍然还活着,他们的观察员通知。

可以使用解决这个问题:

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

+0

这解决了我试图实现的目标。但是为了让我清楚,是一个很好的总结,Observables只能发射值,只有Observer能够订阅/取消订阅Observables?因此Observable不能简单地停止向下游发送值,结束Observer(s)/ Observable的生命周期? – yoonjesung

+0

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(); 

    }); 
}); 


} 
+0

使用observer的complete()方法作为可观察流的空停止的这种想法起作用。然而,我确定了评估者的答案是更好的,因为所有的路由最终都是由观察者自己处理的,观察者只是将必要的数据值发回给观察者。 – yoonjesung