与异步管道混淆的行为(Angular)

Confused behavior with async pipe (Angular)

我会尝试使用异步管道 show/hide 一些等待消息。

app.component.html

<ng-template #isWait>
    <h1>Please wait</h1>
</ng-template>

<div *ngIf="wait | async; else isWait">
    <hello name="{{ name }}"></hello>

    <p>
        Start editing to see some magic happen :)
    </p>

</div>

<button (click)="toggle()">Toggle</button>

<!-- Doesn't change -->
<div style="margin:1rem;">
    Doesn't change here
    <span style="color:red;">Value is {{wait | async}}</span>
  (AppComponent)
</div>

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name: string = 'Angular 5';
  wait: Observable<boolean>;

  constructor(public waitService: WaitService) {
    this.wait = this.waitService.wait;
  }

  toggle() {
    this.waitService.toggle();
  }
}

wait.service.ts

export class WaitService {
  wait: Observable<boolean>;
  private _wait: boolean = false;
  private _onChange: EventEmitter<boolean> = new EventEmitter();

  constructor() {
    this.wait = Observable.create((obs: any) => {
      obs.next(this._wait);
      this._onChange.subscribe((w: boolean) => {
        if (this._wait !== w) {
          this._wait = w;
          obs.next(this._wait);
        }
      });
    });
  }

  toggle() {
    this._onChange.emit(!this._wait);
  }
}

我有 WaitService with wait 属性 和方法 toggle 用于切换等待。 当我尝试切换 wait 时,它在一种情况下有效,但对其他情况无效(如我所料)。

所以,这让我很困惑。 我会试着弄清楚为什么会这样。

示例:https://stackblitz.com/edit/angular-fwghfj

如果您单击“切换”按钮,等待消息不会发生任何变化,但会发出 Wait2Component 中的订阅,并且每次您单击“切换”时都会将其写入控制台输出。

但是在订阅注释行后,显示和隐藏等待消息会正常工作,但在其他地方等待仍然没有变化。

当然我可以将 wait 更改为布尔值并且不关心 async 的这种情况,但这对我来说是意想不到的行为。

您可以这样编写 WaitService:

import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs/BehaviorSubject";

@Injectable()
export class WaitService
{
    private readonly isWaiting = new BehaviorSubject(false);
    public readonly wait$ = this.isWaiting.asObservable();
    public toggle()
    {
        this.isWaiting.next(!this.isWaiting.value);
    }
}

问题在于,对于每个订阅者,都会调用 Observable.create 的回调,这就是您修改 this._wait 状态的地方。换句话说,当您调用 toggle() 时,this._onChange.subscribe()next 句柄被调用,例如。五次甚至更多。但是只有第一个调用会通知它的观察者,因为 this._wait !== w.

避免这种情况的一个简单方法是与 share() 运算符共享同一个源 Observable。

this.wait = Observable.create((obs: any) => {
  // ...
}).share();

但更好的解决方案是不在 Observable.create 中调用 subscribe() 并仅使用带有 do() 的运算符链来执行任何副作用:

this.wait = this._onChange
  .filter((w: boolean) => w !== this._wait)
  .do((w: boolean) => this._wait = w)
  .share();

这应该会产生相同的结果。

看到你更新的演示:https://stackblitz.com/edit/angular-nbgmz7?file=app%2Fservices%2Fwait.service.ts

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name: string = 'Angular 5';
  wait: Observable<boolean>;

  constructor(public waitService: WaitService) {
    this.wait = this.waitService.waitingStatus();
  }

  toggle() {
    this.waitService.toggle();
  }
}

您的服务

@Injectable()
export class WaitService {
  private currentWaitingStatus: boolean = false;
  private waitingStatus$: Subject<boolean> = new BehaviorSubject<boolean>(this.currentWaitingStatus)

  waitingStatus(): Observable<boolean> {
     return this.waitingStatus$
  }

  toggle() {
     this.currentWaitingStatus= !this.currentWaitingStatus
     this.waitingStatus$.next(this.currentWaitingStatus)
  }
}

我更喜欢 return 我 属性 的方法而不是 public.

因为,你的组件肯定不知道你的service里面怎么样。如果你的服务被 n 个客户使用,明天你想更改你的名称 属性 你必须在所有地方都更改它

否则,如果您将其抽象为一种方法,您会在服务的某个位置更改 juste