perf(router): apply prioritizedGuardValue operator to optimize CanLoad guards (#37523)
CanLoad guards are processed in asynchronous manner with the following rules: * If all guards return `true`, operator returns `true`; * `false` and `UrlTree` values wait for higher priority guards to resolve; * Highest priority `false` or `UrlTree` value will be returned. `prioritizedGuardValue` uses `combineLatest` which in order subscribes to each Observable immediately (not waiting when previous one completes that `concatAll` do). So it makes some advantages in order to run them concurrently. Respectively, a time to resolve all guards will be reduced. PR Close #37523
This commit is contained in:

committed by
Alex Rickabaugh

parent
a5ffca0576
commit
d7dd2959c8
@ -7,11 +7,12 @@
|
||||
*/
|
||||
|
||||
import {Injector, NgModuleRef} from '@angular/core';
|
||||
import {EmptyError, from, Observable, Observer, of} from 'rxjs';
|
||||
import {catchError, concatAll, every, first, map, mergeMap, tap} from 'rxjs/operators';
|
||||
import {EmptyError, Observable, Observer, of} from 'rxjs';
|
||||
import {catchError, concatAll, first, map, mergeMap, tap} from 'rxjs/operators';
|
||||
|
||||
import {LoadedRouterConfig, Route, Routes} from './config';
|
||||
import {CanLoadFn} from './interfaces';
|
||||
import {prioritizedGuardValue} from './operators/prioritized_guard_value';
|
||||
import {RouterConfigLoader} from './router_config_loader';
|
||||
import {defaultUrlMatcher, navigationCancelingError, Params, PRIMARY_OUTLET} from './shared';
|
||||
import {UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree} from './url_tree';
|
||||
@ -321,7 +322,7 @@ class ApplyRedirects {
|
||||
const canLoad = route.canLoad;
|
||||
if (!canLoad || canLoad.length === 0) return of(true);
|
||||
|
||||
const obs = from(canLoad).pipe(map((injectionToken: any) => {
|
||||
const canLoadObservables = canLoad.map((injectionToken: any) => {
|
||||
const guard = moduleInjector.get(injectionToken);
|
||||
let guardVal;
|
||||
if (isCanLoad(guard)) {
|
||||
@ -332,20 +333,21 @@ class ApplyRedirects {
|
||||
throw new Error('Invalid CanLoad guard');
|
||||
}
|
||||
return wrapIntoObservable(guardVal);
|
||||
}));
|
||||
});
|
||||
|
||||
return obs.pipe(
|
||||
concatAll(),
|
||||
tap((result: UrlTree|boolean) => {
|
||||
if (!isUrlTree(result)) return;
|
||||
return of(canLoadObservables)
|
||||
.pipe(
|
||||
prioritizedGuardValue(),
|
||||
tap((result: UrlTree|boolean) => {
|
||||
if (!isUrlTree(result)) return;
|
||||
|
||||
const error: Error&{url?: UrlTree} =
|
||||
navigationCancelingError(`Redirecting to "${this.urlSerializer.serialize(result)}"`);
|
||||
error.url = result;
|
||||
throw error;
|
||||
}),
|
||||
every(result => result === true),
|
||||
);
|
||||
const error: Error&{url?: UrlTree} = navigationCancelingError(
|
||||
`Redirecting to "${this.urlSerializer.serialize(result)}"`);
|
||||
error.url = result;
|
||||
throw error;
|
||||
}),
|
||||
map(result => result === true),
|
||||
);
|
||||
}
|
||||
|
||||
private lineralizeSegments(route: Route, urlTree: UrlTree): Observable<UrlSegment[]> {
|
||||
|
Reference in New Issue
Block a user