【发布时间】:2019-08-28 09:17:50
【问题描述】:
注意:请向下滚动到“更新”,因为问题归结为
@Injectable服务被多次实例化。
我有一个加载业务的解析器:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any {
this._logger.debug('Loading application data.');
return forkJoin([
this._userService.getMe(),
this._businessService.getAll()
]).pipe(
tap(([user, businesses]) => {
this._appState.user = user;
this._appState.businesses = businesses;
}),
finalize(() => this._logger.debug('Application data loaded.'))
);
}
有一个ApplicationState 有两个BehaviorSubject 成员_business 和_businesses:
constructor() {
this.businessChange = this._business.asObservable();
this.businessesChange = this._businesses.asObservable();
}
set business(business: BusinessModel) {
console.log(business);
this._business.next(business);
}
get business(): BusinessModel {
return this._business.getValue();
}
set businesses(value) {
this._businesses.next(value);
console.log(this.businesses);
}
get businesses(): Array<BusinessModel> {
return this._businesses.getValue();
}
如您所见,上述状态的businesses 已在解析器中设置。 business 但是取决于路由并根据该路由设置在(延迟加载的)模块中:
ngOnInit() {
this._appState.businessesChange.subscribe(
(b) => {
console.log('businessesChange');
console.log(b);
}
);
this._subscriptions.add(
this._activatedRoute.params
.subscribe((params) => {
this._routeParams = params;
const businessId: number = parseInt(params['businessId'], 10);
const businesses = this._appState.businesses;
console.log(`businessId ${businessId}`);
console.log('available businesses');
console.log(businesses);
this._appState.business = businesses.find(b => b.id === businessId);
})
);
}
这是相关的日志输出:
2019-08-28T09:11:04.989Z DEBUG [..~df7ced28.js:428] Loading application data.
ngx-logger.js:251 2019-08-28T09:11:04.992Z DEBUG [main.js:398] Fetching /me
application.state.ts:56 Set businesses:
application.state.ts:58 (3) [{…}, {…}, {…}]
ngx-logger.js:251 2019-08-28T09:11:06.781Z DEBUG Application data loaded.
businesses.component.ts:43 businessesChange
businesses.component.ts:44 []
businesses.component.ts:47 businessId 4
businesses.component.ts:48 available businesses
businesses.component.ts:49 []
application.state.ts:46 Set business:
application.state.ts:47 undefined
ngx-logger.js:251 2019-08-28T09:11:08.386Z DEBUG Place is null. No action.
如您所见,businesses 被设置并包含三个元素。然后我们看到 应用程序数据已加载。 来自解析器。之后,我们看到_activatedRoute.params 订阅指出该路由显示了4 的businessId,但随后..this._appState.businesses 突然变成了一个空列表——BehaviorSubject 的初始值,尽管我们早点打印出来。
由于我也在记录/调试set 方法,我可以看到在设置为三个元素的列表后,该值不会发生变化。
我不知道这里发生了什么。什么可能导致这种情况?
我已经尝试过的:
- 重启服务器
- 使用调试器(但我还是 printf-debug)
更新
好的,我已将问题归结为ApplicationState 不止一次被实例化:
通过给ApplicationState 一个简单的ID(时间戳):
constructor() {
this.businessChange = this._business.asObservable();
this.businessesChange = this._businesses.asObservable();
this.timestamp = moment().format('MM.SS SSS');
console.log(`${this.timestamp} ApplicationState created`);
}
并在 set 和 get 方法中更改日志输出,我明白了:
08.09 095 ApplicationState created
ngx-logger.js:251 2019-08-28T09:51:16.098Z DEBUG Loading application data.
ngx-logger.js:251 2019-08-28T09:51:16.099Z DEBUG [main.js:398] Fetching /me
:4200/#/businesses/4/calendar:1 This site does not have a valid SSL certificate! Without SSL, your site's and visitors' data is vulnerable to theft and tampering. Get a valid SSL certificate before releasing your website to the public.
application.state.ts:60 08.09 095 Set businesses:
application.state.ts:62 (3) [{…}, {…}, {…}]
application.state.ts:38 08.14 145 ApplicationState created
ngx-logger.js:251 2019-08-28T09:51:16.161Z DEBUG Application data loaded.
businesses.component.ts:43 businessesChange
businesses.component.ts:44 []
businesses.component.ts:54 businessId 4
businesses.component.ts:55 available businesses
businesses.component.ts:56 []
application.state.ts:50 08.14 145 Set business:
application.state.ts:51 undefined
ngx-logger.js:251 2019-08-28T09:51:16.178Z DEBUG Place is null. No action.
calendar.component.ts:105
所以有一个08.09 095 (A) 和一个08.14 145 (B) 实例ApplicationState。
A 设置了业务,但显然使用了进一步的 B。
我检查了,ApplicationState 在我的ApplicationModule 中只导入一次:
providers: [
// Services
ApplicationState,
ApiServices,
ApplicationResolver,
]
那么为什么会这样呢?这不应该是单例吗?是不是因为这超出了延迟加载的模块?
但最重要的是:为什么这在过去几周内奏效了?
我现在还添加了providedIn:
@Injectable({providedIn: 'root'})
export class ApplicationState {
但它的行为仍然相同。
【问题讨论】:
-
如果在取值的时候真的订阅了behavioursubjects,业务还是空的吗?
-
@JelleBruisten 刚试过.. 还是空的O_o
-
@JelleBruisten 我更新了日志输出和代码。
businessesChange是_businesses的 observable。 -
似乎 behaviorSubject 值没有更新,即使在新订阅上,behavioursubject 也应始终输出最新值。因此看起来可能 applicationState 对象与以前使用的不一样?
-
@JelleBruisten 是的,我刚刚检查了这个(请参阅我的更新)。显然它被实例化了两次?这应该发生吗?我 thoguth 注射剂是单例的并且只被实例化一次?
标签: angular typescript