Paul
Paul

Reputation: 51

Execute Resolvers in Route Hierarchy in Parallel in Angular?

With a hierarchical route structure, I would like to get the resolvers along a particular branch to execute in parallel.

The Setup

Currently I have my routing setup like this:

app-routing.module.ts:

const routes: Routes = [
  {
    path: 'route1',
    loadChildren: () =>
      import('./route1/route1.module').then((m) => m.Route1Module),
  },
];

route1-routing.module.ts:

const routes: Routes = [
  { path: '', 
    component: Route1Component,
    resolve: {
      route1: Route1Resolver
    },
    children: [{
      path: 'subroute1',
      loadChildren: () =>
        import('../subroute1/subroute1.module').then((m) => m.Subroute1Module),
    }]
  }
];

subroute1-routing.module.ts:

const routes: Routes = [
  {
    path: '',
    component: Subroute1Component,
    resolve: { subroute1: SubRoute1Resolver },
  },
];

And then just for illustration purposes we have the two resolvers with different delays:

export class Route1Resolver implements Resolve<any> {
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    console.log('Route1 starting')
    return timer(6000).pipe(take(1), tap(_ => {console.log("Route1 finished")} ));
  }
}
export class SubRoute1Resolver implements Resolve<any> {
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    console.log('SubRoute 1 started')
    return timer(3000).pipe(take(1), tap(_ => {console.log("SubRoute1 finished")} ));
  }
}

The Output

When I visit http://localhost:4200/route1/subroute1, and I'm watching the console, every time I see that the Route1 resolver has to finish before the SubRoute1 resolver can start.

Route1 starting
Route1 finished
SubRoute 1 started
SubRoute1 finished

The Problem

The sequential execution of these resolvers introduces an undesirable delay. Ideally these two resolvers can execute in parallel, and once the last one finishes and all of the data is in, then Angular can move on to rendering what is in the <router-outlet>.

The Question

Is there a way to have these resolvers execute in parallel?

Less desirable solutions

Upvotes: 0

Views: 396

Answers (1)

Paul
Paul

Reputation: 51

I may have been thinking of this the wrong way. There are probably likely two cases here why we would want to load some kind of data asynchronously in an ancestor route:

  1. It is non-critical data required by a sub-component in the ancestor component tree (in otherwords for a component outside of the <router-outlet>). If this is the case then it could be that the responsibility of data fetching is delegated to the components, not a resolver in the routes. In this case "non-critical" means you would not interrupt the users navigation if the data was not there, to 404 for example.

  2. It is critical data. In this case the descendent resolver (SubRoute1 in the example given) would have to bare some responsibility. Though the extent of that responsibility could be abstracted away:

    1. The Route1Resolver can setup the Observable to do the data fetch, and then place it somewhere where it is accessible but will not be subscribed to by the framework. Either place it in a Service, or wrap the observable in an observable and return that so it is available through route data. Eg, return of(myDataFetchObsersable$)
    2. The SubRoute1Resolver would be responsible for retrieving the observable from Route1Resolver and integrating with it, probably with rxjs' combineLatest.

Upvotes: 0

Related Questions