具有 switchMap 重复输出的路由器事件
Router event with switchMap duplicated output
我已经解决了我的问题,但我想了解为什么会这样。
我正在苦苦思索阅读之类的东西,但找不到为什么它会在订阅块上复制输出。
这是代码
的 stackblitz
https://stackblitz.com/edit/angular-szwnz7
我的思路是。
在该组件上,在 NavigationEnd 类型的每个路由器事件上,我想获取部分 ID。
但是我对路由器事件中的任何内容都不感兴趣。
所以我用 activatedRoute.queryParamMap
Observable 做了一个 switchMap
,在订阅块中获取 ID 号。
每次我在链接之间单击时,它都会显示两个 console.logs。
假设 this.route.queryParamMap
作为 BehaviorSubject,这意味着一旦您订阅它,您就会获得现有值,然后新值会到达。
现在解释一下您的代码,当您单击 link:
时会发生什么
this.router.events
发出新的 NavigationEnd 然后你切换到 this.route.queryParamMap
this.route.queryParamMap
具有现有值并且该现有值到达订阅
this.route.queryParamMap
您现在已经订阅了这个 Observable。由于导航,新的价值也到达这里。 this.router.events
和 this.route.queryParamMap
都是独立的 Observables 并且在导航时都会发出。所以这就像竞争条件。由于 this.router.events
切换到 this.route.queryParamMap
的现有值,您获得第一个值,另一个直接来自 this.route.queryParamMap
。这就是另一个值到达订阅的原因。
我认为首先要提到的是 queryParamMap
派生自 queryParams
,这是一个 BehaviorSubject
:
function createActivatedRoute(c: ActivatedRouteSnapshot) {
return new ActivatedRoute(
new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams),
new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);
}
下面是 queryParamMap
的获得方式:
get queryParamMap(): ParamMap {
if (!this._queryParamMap) {
this._queryParamMap = convertToParamMap(this.queryParams);
}
return this._queryParamMap;
}
在幕后,创建了一个 stream of transitions。因此,当您单击一个按钮时,新转换 将被推送到该流中,这意味着必须激活:
export const activateRoutes =
(rootContexts: ChildrenOutletContexts, routeReuseStrategy: RouteReuseStrategy,
forwardEvent: (evt: Event) => void): MonoTypeOperatorFunction<NavigationTransition> =>
map(t => {
new ActivateRoutes(
routeReuseStrategy, t.targetRouterState!, t.currentRouterState, forwardEvent)
.activate(rootContexts);
return t;
});
这将导致调用 advanceActivatedRoute
并最终达到 this line:
(<any>route.queryParams).next(nextSnapshot.queryParams);
所以这应该是记录到控制台的第一条消息。
下一个是由于 NavigationEnd
event:
(this.events as Subject<Event>)
.next(new NavigationEnd(
t.id, this.serializeUrl(t.extractedUrl), this.serializeUrl(this.currentUrlTree)));
如果你想可视化这个,你可以打开这个StackBlitz,打开开发工具并放置一些断点:
- router_link.ts: 265 - 当你点击一个按钮时
- activated_routes.ts: 25 - 当路由被激活时
- router.ts: 1062 -
NavigationEnd
事件
- router_state.ts: 390 -
advanceActivatedRoute
的body(在路由激活过程中)
- app.component.ts
我已经解决了我的问题,但我想了解为什么会这样。
我正在苦苦思索阅读之类的东西,但找不到为什么它会在订阅块上复制输出。
这是代码
的 stackblitzhttps://stackblitz.com/edit/angular-szwnz7
我的思路是。
在该组件上,在 NavigationEnd 类型的每个路由器事件上,我想获取部分 ID。
但是我对路由器事件中的任何内容都不感兴趣。
所以我用 activatedRoute.queryParamMap
Observable 做了一个 switchMap
,在订阅块中获取 ID 号。
每次我在链接之间单击时,它都会显示两个 console.logs。
假设 this.route.queryParamMap
作为 BehaviorSubject,这意味着一旦您订阅它,您就会获得现有值,然后新值会到达。
现在解释一下您的代码,当您单击 link:
时会发生什么this.router.events
发出新的 NavigationEnd 然后你切换到this.route.queryParamMap
this.route.queryParamMap
具有现有值并且该现有值到达订阅this.route.queryParamMap
您现在已经订阅了这个 Observable。由于导航,新的价值也到达这里。this.router.events
和this.route.queryParamMap
都是独立的 Observables 并且在导航时都会发出。所以这就像竞争条件。由于this.router.events
切换到this.route.queryParamMap
的现有值,您获得第一个值,另一个直接来自this.route.queryParamMap
。这就是另一个值到达订阅的原因。
我认为首先要提到的是 queryParamMap
派生自 queryParams
,这是一个 BehaviorSubject
:
function createActivatedRoute(c: ActivatedRouteSnapshot) {
return new ActivatedRoute(
new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams),
new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);
}
下面是 queryParamMap
的获得方式:
get queryParamMap(): ParamMap {
if (!this._queryParamMap) {
this._queryParamMap = convertToParamMap(this.queryParams);
}
return this._queryParamMap;
}
在幕后,创建了一个 stream of transitions。因此,当您单击一个按钮时,新转换 将被推送到该流中,这意味着必须激活:
export const activateRoutes =
(rootContexts: ChildrenOutletContexts, routeReuseStrategy: RouteReuseStrategy,
forwardEvent: (evt: Event) => void): MonoTypeOperatorFunction<NavigationTransition> =>
map(t => {
new ActivateRoutes(
routeReuseStrategy, t.targetRouterState!, t.currentRouterState, forwardEvent)
.activate(rootContexts);
return t;
});
这将导致调用 advanceActivatedRoute
并最终达到 this line:
(<any>route.queryParams).next(nextSnapshot.queryParams);
所以这应该是记录到控制台的第一条消息。
下一个是由于 NavigationEnd
event:
(this.events as Subject<Event>)
.next(new NavigationEnd(
t.id, this.serializeUrl(t.extractedUrl), this.serializeUrl(this.currentUrlTree)));
如果你想可视化这个,你可以打开这个StackBlitz,打开开发工具并放置一些断点:
- router_link.ts: 265 - 当你点击一个按钮时
- activated_routes.ts: 25 - 当路由被激活时
- router.ts: 1062 -
NavigationEnd
事件 - router_state.ts: 390 -
advanceActivatedRoute
的body(在路由激活过程中) - app.component.ts