Angular Route Resolver用Subscribe无效,用take(1)正常的原因排查
1. 你的第一个resolve方法为什么异常?
看你第一个resolve的代码:
resolve() : Observable<INews> { return this.newsService.getnonpaginatednews().pipe( map(resp => { return this.news = resp.result; }) ) }
这里你用map把HTTP返回的整个resp转换成了resp.result,也就是说最终传递给路由route.data['newsData']的是resp.result的值,而非完整的resp对象。
但你的组件代码里仍在尝试从newsData中取result:
getnonpaginatednews(){ let nonPaginatedNews = this.route.snapshot.data['newsData']; this.nonPaginatedNews = nonPaginatedNews.result; }
此时newsData本身就是resp.result,它没有result属性,自然会抛出异常。
另外,HTTP请求返回的Observable本身会在发送请求后自动完成,不需要额外操作,你这里的核心错误是数据转换和组件取值逻辑不匹配。
2. 为什么用subscribe会无效?
如果在resolve里直接调用subscribe,比如:
resolve() { this.newsService.getnonpaginatednews().subscribe(resp => { this.news = resp.result; }) }
这种写法的问题在于:Resolver要求返回Observable/Promise/具体值,Angular会自动订阅这个Observable,等待它完成后再激活路由并把数据存入route.data。但直接调用subscribe返回的是Subscription对象,Resolver无法识别,会直接激活路由,此时HTTP请求还未完成,route.data里没有数据,组件取值自然为空。
3. 第二个方法为什么能正常工作?
你的第二个resolve代码:
resolve() : Observable<INews> { return this.newsService.getnonpaginatednews().pipe(take(1)) }
这里没有做map转换,返回的是完整的HTTP响应对象,所以组件里route.data['newsData']拿到的是整个resp,取resp.result是正确的。
至于take(1),其实对HTTP请求来说不是必须的——因为HTTP的Observable本身只会发射一次数据然后自动完成。但take(1)能确保Observable在拿到第一个值后就完成,避免特殊场景下Observable不完成导致Resolver一直等待的问题,所以加上也没坏处。
正确写法参考
如果想在resolve里只传递resp.result给组件,需修改组件的取值逻辑:
// resolve方法 resolve() : Observable<INews> { return this.newsService.getnonpaginatednews().pipe( map(resp => resp.result) // 直接返回resp.result,无需赋值给this.news ) } // 组件方法 getnonpaginatednews(){ this.nonPaginatedNews = this.route.snapshot.data['newsData']; // 直接使用,不用再取result }
或者保持resolve返回完整响应,组件正常取result,就像你第二个方法那样,也是可行的。
内容的提问来源于stack exchange,提问作者user10913305

