订阅发布BehaviorSubject
发布:在统一的服务中
js
triggerInitConfigChange$ = new BehaviorSubject<DynamicQuery>(this._dynamicQuery); //_dynamicQuery是参数
this.triggerInitConfigChange$.next(this._dynamicQuery);
订阅1:在特定的组件中
js
this._subscription = this.tabService.triggerInitConfigChange$.subscribe(
(res) => {
// 提取开始,结束时间,查询参数
this.fuzzyValue = res.queryParams;
this.dateTimeOptions = {
startTime: new Date(res.startTime || Date.now() - 7 * 24 * 60 * 60 * 1000),
endTime: new Date(res.endTime || Date.now()),
lineBreak: true,
cssClass: 'has-border',
key: 'custom',
};
this.activeRoute.queryParams.subscribe((queryParams) => {
if (queryParams.opSate === '0') {
const dynamicFilter: DynamicFilter[] = [];
dynamicFilter.push({
key: 'op_state',
checked: true,
operator: 'is',
value: [0],
value_type: 'list',
});
this.tabService.updateDynamicQuery(dynamicFilter, 'dynamicFilter');
this.tabService.updateDynamicQuery('', 'startTime');
this.tabService.updateDynamicQuery('', 'endTime');
} else {
}
});
this.cdr.markForCheck();
},
(error) => {
console.error(error);
},
);
订阅2:在特定的组件中
js
this._subscription4 = this.tabService.triggerInitConfigChange$.subscribe((res) => {
this.exportOption.params.query_param = res.queryParams;
this.exportOption.params.dyn_filter = res.dynamicFilter;
this.exportOption.params.start_time = res.startTime;
this.exportOption.params.end_time = res.endTime;
});
产生的问题:共享状态的一致性
BehaviorSubject
的 next
方法发送的是值的引用而不是值本身。这意味着当你调用 next
时,它将发送当前值的引用给所有已订阅的观察者,而不会克隆值。这可以导致潜在的共享状态问题,因为多个观察者可以访问和修改相同的引用。
如果你需要确保不会出现共享状态问题,你可以在发送新值之前进行深拷贝,以确保每个订阅者都接收到一个独立的副本而不是引用。你可以使用不同的方法,如 Lodash 的 _.cloneDeep
或 JSON.parse(JSON.stringify())
来深拷贝对象。例如:
js
const triggerInitConfigChange$ = new BehaviorSubject({ name: "John" });
// 第一个订阅者
const subscription1 = triggerInitConfigChange$.subscribe((value) => {
console.log("Subscriber 1:", value);
});
// 在发送新值之前进行深拷贝
const newValue = _.cloneDeep(triggerInitConfigChange$.getValue());
newValue.name = "Alice";
// 发送新值
triggerInitConfigChange$.next(newValue);
// 第二个订阅者
const subscription2 = triggerInitConfigChange$.subscribe((value) => {
console.log("Subscriber 2:", value);
});
// 输出:
// Subscriber 1: { name: "Alice" }
// Subscriber 2: { name: "Alice" }
在上面的示例中,我们在发送新值之前使用 _.cloneDeep
进行了深拷贝,以确保两个订阅者获得的值是相互独立的,而不会相互影响。
所以说:如果不进行深拷贝,可能造成多个订阅者获得的内容不一样,或者在发布之后,这个值再进行使用会失真
如果发布的时候没有进行深拷贝,那么我们就要把那个发布的值在发布之前拷贝下来,这样才能在本文件中使用到正确的值!
例如:我在统一的服务文件里面,发布之后,又使用了发布的值当作查询参数:
js
this.cloneObj = JSON.parse(JSON.stringify(this._dynamicQuery)); //提前拷贝要发布的值
this.triggerInitConfigChange$.next(this._dynamicQuery); //发布
getEventList(d): void {
console.log("这是参数");
console.log(this.cloneObj);
console.log("这是参数");
this.httpClient.post('/judgeOperation/v1/op_event/overview_events', {
dyn_filter: d,
// start_time: this._dynamicQuery.startTime, //这样不行,因为this._dynamicQuery可能已经被改变了
start_time: this.cloneObj.startTime, //使用我们拷贝下来的值
// end_time: this._dynamicQuery.endTime, //这样不行,因为this._dynamicQuery可能已经被改变了
end_time: this.cloneObj.endTime, //使用我们拷贝下来的值
query_param: this._dynamicQuery.queryParams,
order: this._listLastedConfig.order,
order_column: this._listLastedConfig.orderColumn,
page: this._listLastedConfig.page,
page_size: this._listLastedConfig.pageSize,
// 标记页面跳转来源
origin: this._otherParams.origin
}).subscribe(res => {
this.triggerListDataChange$.next(res);
this.behaviorService.triggerLoadingChange$.next([]);
}, error => {
this.triggerListDataChange$.next(error);
this.behaviorService.triggerLoadingChange$.next([]);
});
}