如何高效处理Angular 5路由中的多个resolve?AngularJS迁移开发者疑问
从AngularJS到Angular 5:高效处理路由多个Resolve的技巧
刚从AngularJS搭配ui-router转过来,肯定会觉得Angular的resolve写法一下子“繁琐”了不少——毕竟以前在路由里写几个return,控制器里直接注入就能用,现在好像要写一堆代码?其实是咱们还没摸透它的高效玩法,下面就给你拆解一下怎么优雅处理多个resolve:
先回忆下你熟悉的AngularJS写法
先确认下咱们的共识,AngularJS + ui-router里你是这么玩的:
// 路由配置里的resolve $stateProvider.state('myState', { resolve: { something: function(SomeService) { return SomeService.getSomething(); }, somethingElse: function(AnotherService) { return AnotherService.getSomethingElse(); } }, controller: 'MyController' }); // 控制器直接注入使用 .controller('MyController', function(something, somethingElse) { console.log(something, somethingElse); });
这种写法确实简洁,但Angular的resolve机制其实是把“数据获取”和“路由逻辑”做了更清晰的分离,掌握技巧后同样能写得很清爽。
Angular 5里高效处理多个Resolve的方法
方法1:路由直接配置resolve,抽离逻辑到服务
不要把数据获取的逻辑写在路由配置里,而是封装到专门的服务中,路由只负责调用服务方法:
- 第一步:封装数据获取服务
import { Injectable } from '@angular/core'; import { SomeService } from './some.service'; import { AnotherService } from './another.service'; @Injectable() export class DataFetchService { constructor( private someService: SomeService, private anotherService: AnotherService ) {} // 封装每个resolve需要的数据请求 fetchSomething() { return this.someService.getSomething(); } fetchSomethingElse() { return this.anotherService.getSomethingElse(); } }
- 第二步:路由配置里调用服务方法
import { Routes } from '@angular/router'; import { MyComponent } from './my.component'; import { DataFetchService } from './data-fetch.service'; import { inject } from '@angular/core'; const routes: Routes = [ { path: 'my-page', component: MyComponent, resolve: { // Angular 14+可以用inject直接获取服务,更早版本可以用Resolve类 something: () => inject(DataFetchService).fetchSomething(), somethingElse: () => inject(DataFetchService).fetchSomethingElse() } } ];
- 第三步:组件中获取resolve的数据
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({...}) export class MyComponent implements OnInit { something!: any; somethingElse!: any; constructor(private route: ActivatedRoute) {} ngOnInit() { // 从路由快照中获取resolve的数据 this.something = this.route.snapshot.data['something']; this.somethingElse = this.route.snapshot.data['somethingElse']; // 如果是动态路由(比如参数变化),需要订阅data的变化 // this.route.data.subscribe(data => { // this.something = data['something']; // this.somethingElse = data['somethingElse']; // }); } }
方法2:使用Resolve守卫类,拆分维护多个resolve
如果每个resolve的逻辑比较复杂,或者需要单独复用,可以给每个resolve写一个守卫类,这样代码更易维护:
- 创建单独的Resolve守卫
// SomethingResolver.ts import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { SomeService } from './some.service'; @Injectable() export class SomethingResolver implements Resolve<any> { constructor(private someService: SomeService) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { return this.someService.getSomething(); } } // SomethingElseResolver.ts import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { AnotherService } from './another.service'; @Injectable() export class SomethingElseResolver implements Resolve<any> { constructor(private anotherService: AnotherService) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { return this.anotherService.getSomethingElse(); } }
- 路由配置中引入守卫
import { Routes } from '@angular/router'; import { MyComponent } from './my.component'; import { SomethingResolver } from './something.resolver'; import { SomethingElseResolver } from './something-else.resolver'; const routes: Routes = [ { path: 'my-page', component: MyComponent, resolve: { something: SomethingResolver, somethingElse: SomethingElseResolver } } ];
- 组件中获取数据的方式和方法1完全一致
进阶技巧:合并多个无依赖的resolve请求
如果多个resolve之间没有依赖关系(不需要等一个请求完成再发另一个),可以用forkJoin同时发起请求,减少整体等待时间:
import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { forkJoin } from 'rxjs'; import { map } from 'rxjs/operators'; import { SomeService } from './some.service'; import { AnotherService } from './another.service'; @Injectable() export class CombinedResolver implements Resolve<{something: any, somethingElse: any}> { constructor( private someService: SomeService, private anotherService: AnotherService ) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { // 同时发起两个请求,全部完成后返回合并的数据 return forkJoin([ this.someService.getSomething(), this.anotherService.getSomethingElse() ]).pipe( map(([something, somethingElse]) => ({ something, somethingElse })) ); } }
然后路由配置里只需要加一个resolve:
resolve: { combinedData: CombinedResolver }
组件里获取:
ngOnInit() { const { something, somethingElse } = this.route.snapshot.data['combinedData']; // 直接使用两个数据 }
总结一下
Angular的resolve机制其实是把数据获取的逻辑和路由配置做了更清晰的职责分离,只要记住这几个核心技巧,处理多个resolve就不会觉得代码冗余:
- 把数据获取逻辑抽离到服务,路由只做调用
- 复杂逻辑用单独的Resolve守卫类,方便维护和复用
- 无依赖的请求用
forkJoin合并,提升加载效率
这样写出来的代码不仅清晰,还能复用,完全能达到AngularJS里那种简洁高效的效果~
内容的提问来源于stack exchange,提问作者deonclem
相关产品推荐
相关产品推荐

