首页 > 解决方案 > 在将文件保存到存储之后,如何处理与调用在 Firestore 上创建新对象的方法相关的错误情况?

问题描述

我不太喜欢 Angular 和 Firebase,我有以下问题。

我有以下代码来处理用户注册的整个周期。它部分有效,但我有一个问题,我将尝试详细解释(可能是因为我在函数式编程方面仍然遇到一些困难......):

createUser(user, file) {
  console.log(user);

  if(user.password != user.password_confirmation) {
    let passwordError: any = new Object();
    passwordError["message"] = "Inserted password and inserted password confirmation are different";
    this.eventAuthError.next(passwordError);
  }
  else {
    this.afAuth.auth.createUserWithEmailAndPassword(user.email, user.password)
      .then( userCredential => {
        this.newUser = user;
        console.log(userCredential);
        userCredential.user.updateProfile( {
          displayName: user.firstName + ' ' + user.lastName
        });

        this.uploadFileIntoFirebaseStore(file);


        this.insertUserData(userCredential, this.downloadURL)
          .then(() => {
            this.router.navigate(['/home']);
          });
      })
      .catch( error => {
        console.log(error);
        console.log(typeof error);
        this.eventAuthError.next(error);    // Emit the event passing the error object
      });
    }
}

uploadFileIntoFirebaseStore(fileToBeUploaded) {
  var n = Date.now();
  const filePath = `user_avatar/${n}`;
  const fileRef = this.storage.ref(filePath);

  const task = this.storage.upload(`user_avatar/${n}`, fileToBeUploaded);
  task
    .snapshotChanges()
    .pipe(
      finalize(() => {
        this.downloadURL = fileRef.getDownloadURL();
        this.downloadURL.subscribe(url => {
          if (url) {
            this.fb = url;
          }
          console.log(this.fb);
        });
      })
    )
    .subscribe(url => {
      if (url) {
        console.log(url);
      }
    });

    return this.fb

}

insertUserData(userCredential: firebase.auth.UserCredential, userAvatar) {

  let userObg = {
        name: this.newUser.firstName,
        surname: this.newUser.lastName,
        complete_name: this.newUser.firstName + " " + this.newUser.lastName,
        email: this.newUser.email,
        role: this.newUser.ruolo_utente,
        avatar: userAvatar
      };

  console.log("USER OBJECT: ", userObg);

  return this.db.doc(`Users/${userCredential.user.uid}`).set(userObg);
}

基本上它做了以下事情:

  1. createUser()获取一个必须保存到 FireStore 集合中的用户对象和一个文件参数该参数是必须保存到 Firebase 存储中的图像。

  2. 首先,它createUserWithEmailAndPassword()使用用户名和密码调用创建一个新用户到 Firebase 身份验证服务(它工作正常)。

  3. 如果正确创建了用户,它会进入then()并调用uploadFileIntoFirebaseStore()用于将图像文件上传到 Firebase 存储的方法。

  4. 然后它调用insertUserData()创建与当前用户相关的新对象并将其保存到 FireStore 的方法。

我的问题发生在第 3 点和第 4 点之间。详细地说,文件已正确保存到 Firebase 存储中,但在我看来这是一个异步任务,因此需要一些时间才能将与此文件相关的 URL 返回到 Firebase 存储中。这需要时间,但与此同时insertUserData()启动了,所以这里这个 URL 字段(我必须保存在我的对象中)是未定义的。

什么是等到文件 URL 被“返回”的聪明方法?也许我不必返回任何东西,但一件好事是在检索 URL 之后将调用insertUserData()(插入 FireStore)放入方法中,这里:uploadFileIntoFirebaseStore()

this.downloadURL.subscribe(url => {
    if (url) {
        this.fb = url;
        // I PUT THE CALL TO HERE
    }
    console.log(this.fb);
});

什么是解决这个问题的聪明方法?

标签: angularfirebasegoogle-cloud-firestorerxjsfirebase-storage

解决方案


您需要.pipe()您的流媒体,否则您将永远无法同步它们。

uploadFileIntoFirebaseStore应该return上传流:

return this.storage.upload(`user_avatar/${n}`, fileToBeUploaded)
  .snapshotChanges()
  .pipe(switchMap(() => fileRef.getDownloadURL());

然后,在你的createUser你可以使用它:

this.uploadFileIntoFirebaseStore(file).subscribe(downloadURL =>
  this.insertUserData(userCredential, downloadURL)
    .then(() => {
      this.router.navigate(['/home']);
    });
  );

推荐阅读