Skip to content

订阅发布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;
});

产生的问题:共享状态的一致性

BehaviorSubjectnext 方法发送的是值的引用而不是值本身。这意味着当你调用 next 时,它将发送当前值的引用给所有已订阅的观察者,而不会克隆值。这可以导致潜在的共享状态问题,因为多个观察者可以访问和修改相同的引用。

如果你需要确保不会出现共享状态问题,你可以在发送新值之前进行深拷贝,以确保每个订阅者都接收到一个独立的副本而不是引用。你可以使用不同的方法,如 Lodash 的 _.cloneDeepJSON.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([]);
    });
}