Angular 10 当嵌套的可观察对象完成时调用 finalize()

Angular 10 call finalize() when nested observables complete

在处理完最后一个项目后完成嵌套的可观察对象。 Stackblitz

finalize() 应该在 observables 完成时调用 - 所有数字 (11, 12, 13) 都被输出。

observable 应该如何嵌套?

import { from } from "rxjs";
import { map, finalize } from "rxjs/operators";

//emit (1,2,3)
const data = [
  {
    userId: 1,
    id: 1
  },
  {
    userId: 1,
    id: 2
  },
  {
    userId: 1,
    id: 3
  }
];
const source = from(data);
//add 10 to each value
const example = source.pipe(map(val => add(val.id)));
//output: 11,12,13
const subscribe = example.subscribe(val => console.log(val));
function add(n) {
  return n + 10;
}

Stackblitz 是一个起点。

在下面的代码中,我想向所有用户发送一条消息。

我想在所有消息发送完后取消订阅并关闭模态。

  submit() {
    const users = from(this.form.value.users).pipe(
      finalize(() => {
        console.log('finalize'),
        this.dismissModal()
      }),
      map(user => this.buildMessage(user))
    ).subscribe(message => {
      this.subscription = this.firestoreService.addMessage(message)
        .subscribe();
    });
  }

  ngOnDestroy(): void {
    this.subscription?.unsubscribe();
  }

  dismissModal() {
    this.dialogRef.close('modal dismissed');
  }

现在 firestoreService.addMessage(message) 记录 console.log('addMessage') 和 returns 但不将消息添加到数据库。

  addMessage(data:Message):Observable<T> {
    console.log('addMessage');
    data.timestamp = firebase.firestore.FieldValue.serverTimestamp();
    return this.authService.currentUser$.pipe(
      switchMap(user => {
        console.log('addMessage user: ', user);
        if (user) {
          return this.firestore
            .collection<any>(user.company)
            .doc(user.licence)
            .collection<any>(message)
            .add(data)
              .then(res => {
                console.log("Message successfully added! ", res);
              })
              .catch(e => {
                console.error("Error adding message: ", e);
              });
          } else {
            return [];
          }
        }
      )
    );
  }

在这种情况下你应该使用高阶运算符switchMap

使用 switchMap,您订阅 buildMessage(user) 并将其可观察结果传递给 firestoreService.addMessage(message),只需一次管道操作。

submit() {
  this.subscription = from(this.form.value.users).pipe(
    finalize(() => {
      console.log('finalize'),
      this.dismissModal()
    }),
    map(user => this.buildMessage(user)),
    switchMap((message) => this.firestoreService.addMessage(message))
  ).subscribe();
}

ngOnDestroy(): void {
  this.subscription?.unsubscribe();
}

dismissModal() {
  this.dialogRef.close('modal dismissed');
}

已编辑

你需要用这种方式return Observables。 from 从 promise 创建 observable of 从序列中的值创建 observable

 addMessage(data:Message):Observable<T> {
    console.log('addMessage');
    data.timestamp = firebase.firestore.FieldValue.serverTimestamp();
    return this.authService.currentUser$.pipe(
      switchMap(user => {
        console.log('addMessage user: ', user);
        if (user) {
          return from(this.firestore
            .collection<any>(user.company)
            .doc(user.licence)
            .collection<any>(message)
            .add(data))
          } else {
            return of([]);
          }
        }
      )
    );
  }