如何在完成另一个函数时调用一个函数?

How to call a function on complition of another one?

我正在学习 Angular 通过建立一个小型房地产代理机构作为一个宠物项目。我有一个带有表单的模态,用户可以在其中添加新的 Estate - 基本数据和图片。首先,我想将它保存到 Cloudinary,然后将 url 保存到 Firebase。

我无法让它按顺序工作,而是首先使用空 urls 数组调用 Firebase。我发现 rxjs 中有函数 finalize() 但它也不起作用。

云服务:

uploadImage(vals: any): Observable<any>{
    return this.http
    .post('https://api.cloudinary.com/v1_1/<my_cloudinary>/image/upload', vals)
   }

FirebaseService 和 IEstate:

addEstate(estate: IEstate){
    return this.firestore.collection('estate').doc().set(estate);
  }

export interface IEstate{
  id?: string;
  city: string;
  street: string;
  links: string[];
}

EstateCreateComponent:

form: FormGroup;
  estates: IEstate[] = [];
  files: File[] = [];

handleSaveEstate(){
    let result : string[];
    this.uploadToCloudinary()
    .pipe(
      finalize(() => this.addEstate(result)))
    .subscribe(res => result = res,
    error =>{
      console.log(error);
    },
    () => {
      console.log('complete')
    });
  }

addEstate(links: string[]): void{
    let data = {
      city: this.form.value.city,
      street: this.form.value.street,
      links: links
    } as IEstate;

    this.firebaseService.addEstate(data).then((res) =>{
      console.log(res);
    });
  }
 uploadToCloudinary(){
    const data = new FormData();
    let urls: string[] = [];
    
    for (let i = 0; i < this.files.length; i++) {
      data.append('file', this.files[i]);
      data.append('upload_preset', 'my_name_upload')
      data.append('cloud_name', 'my_cloudinary_name')

      this.cloudinary.uploadImage(data).subscribe(res =>{
        urls.push(res.secure_url); 
      });
    }

    return of(urls);
  }

Post 对 Cloudinary API 的请求(在 for 循环中)是根据此 link 发出的:cloudinary docs
模态提交按钮触发 handleSaveEstate()。然后我想将所有图片上传到 Cloudinary 并从响应中获取 urls 到 arrray 并在调用 addEstate(urls) 时完成。
首先调用 Friebase,然后填充数组:

如何按顺序拨打这些电话?

这里有多个问题。

  1. 循环内的订阅可能会导致多个打开的订阅。相反,您可以将 RxJS forkJoinArray#map.
  2. 一起使用
  3. 您不能从异步调用中同步 return urls。您需要 return observable 并在需要响应的地方订阅。
  4. 您可以使用 RxJS from 函数将 promise 转换为函数。您要么需要将 promise 转换为 observable,反之亦然。我已经使用 from.
  5. 说明了前者
  6. 使用 switchMap 之类的映射运算符从一个 observable 切换到另一个。

尝试以下方法

form: FormGroup;
estates: IEstate[] = [];
files: File[] = [];

handleSaveEstate() {
  let result: string[];
  this.uploadToCloudinary().pipe(
    switchMap(urls => this.addEstate(urls))
  ).subscribe({
    next: (res) => {
      console.log(res);  // <-- response from `this.firebaseService.addEstate()`
    },
    error: (error) => {
      console.log(error);
    },
    complete: () => {
      console.log('complete')
    }
  });
}

addEstate(links: string[]): Observable<any> {
  let data = {
    city: this.form.value.city,
    street: this.form.value.street,
    links: links
  } as IEstate;

  from(this.firebaseService.addEstate(data));
}

uploadToCloudinary(): Observable<any> {
  const data = new FormData();

  return forkJoin(
    this.files.map(file => {
      data.append('file', file);
      data.append('upload_preset', 'my_name_upload')
      data.append('cloud_name', 'my_cloudinary_name')
      return this.cloudinary.uploadImage(data).pipe(
        map(res => res.secure_url)
      );
    })
  );
}