我使用RxJS的方式如下,得到了意想不到的值顺序.下面的代码可以在Stackblitz中执行.

编辑-简化代码.我们可以简化为两个简单的观察者,对相同的行为主体以不同的顺序接收数据.

this.state$ = new BehaviorSubject<any>({ a: null, b: null });

const obs1 = this.state$
  .subscribe((value) => {
    console.log('obs 1', value);
    if (value.a == 1) this.state$.next({ a: 2, b: 3 });
  });

const obs2 = this.state$.subscribe((value) => console.log('obs 2', value));

this.state$.next({ a: 1, b: 1 });

以下是日志(log)的外观

obs 1 {a: null, b: null}
obs 2 {a: null, b: null}
obs 1 {a: 1, b: 1}
obs 1 {a: 2, b: 3}
obs 2 {a: 2, b: 3}
obs 2 {a: 1, b: 1}

我希望相同行为对象的观察者以相同的顺序接收emits 的值,无论这些值来自哪里.

以前的代码

class sampleState {
  a: any;
  b: any;
}

const initialState: sampleState = {
  a: null,
  b: null,
};

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule],
  template: ``,
})
export class App {
  name = 'Angular';

  protected _state$: BehaviorSubject<sampleState>;
  state$: Observable<sampleState>;

  constructor() {
    this._state$ = new BehaviorSubject<sampleState>(initialState);
    this.state$ = this._state$.asObservable();

    this.select((state) => state.a).subscribe((value) => {
      console.log('a ' + value);
      if (value == 1) this.setState({ b: 3 });
    });

    this.select((state) => state.b).subscribe((value) => {
      console.log('b ' + value);
    });

    this._state$.subscribe((value) => console.log(value));

    this.setState({ a: 1, b: 1 });
  }

  public get state() {
    return this._state$.getValue();
  }

  public setState(newState: any) {
    this._state$.next({
      ...this.state,
      ...newState,
    });
  }

  public select<K>(mapFn: (state: sampleState) => K): Observable<K> {
    return this._state$.asObservable().pipe(
        map((state: sampleState) => mapFn(state)),
       distinctUntilChanged()
    );
  }
}

我得到了以下日志(log)

{a: null, b: null}
{a: 1, b: 3}
{a: 1, b: 1}

虽然我期待着

{a: null, b: null} // initialisation
{a: 1, b: 1} // setState
{a: 1, b: 3} // if a == 1 => set b = 3

在调用下一个setState之前,第一个setState似乎没有完成.有没有一种方法可以改变这种行为,使状态按顺序改变?

推荐答案

您之所以看到这种行为,是因为所有操作都是同步的,并且您正在从" Select 一个"订阅中发出一个新值,这会导致递归地执行订阅逻辑.

为了防止递归行为,您可以这样使用asapScheduler:

this.state$ = this._state$.pipe(observeOn(asapScheduler));

现在,将您的select方法更新为使用this.state$而不是this._state$,您应该可以开始了.

这是一张StackBlitz英镑的钞票,你可以 checkout .

Angular相关问答推荐

iOS Mobile Safari - HTML5视频覆盖一切

Ionic 5角形共享两个模块之间的组件

导致无限请求的Angular HttpInterceptor和HttpClientModule

以17角表示的自定义元素

倒计时计时器,每10秒重新启动一次,共4次

如何使用独立组件在ANGLE(16+)中实现嵌套布线

当我更新S显示的数据时,为什么我的垫表用户界面没有更新?

无法绑定到formControl,因为它不是input的已知属性

RxJS如何按顺序进行POST请求,只有在前一个完成后才会触发新的请求?

Cypress 12.8.1 无法使用条纹元素 iframe

从具有特定 node 值的现有数组创建新数组

Angular APP_INITIALIZER 中的 MSAL 身份验证

无法在 Angular 中使用 CryptoJS 正确加密

Angular combinelatest使用没有初始值的主题

当我ng serve时,Angular CLI 提示TypeError: callbacks[i] is not a function

全局异常处理

使用 Angular2 将文件上传到 REST API

如何以Angular 获取嵌套表单组的控件

Angular 2 - 全局 CSS 文件

Angular:找不到不同的支持对象[object Object]