使用 Firebase 存储和 Firebase 插入/更新用户个人资料图片

Insert / Update user profile picture using Firebase Storage and Firebase

当用户更新您的个人资料图片时,我需要将他的照片上传到 Firebase 存储并立即检索下载 URL 以更新他的个人资料 collection。

另一种情况下,当用户更新他的个人资料时,他没有改变他的个人资料图片,所以我没有imageData,也不需要上传他的照片,只更新他的个人资料信息。

我的saveProfile()方法:

if (this.profileForm.valid) {
....

  //Check if the user change his picture. If yes, the userProfilePicture has data.
  If (userProfilePicture) {
    //upload the picture to firestorage
      const path = `/profile/${this.profile.id}.jpg`;
      const task =  this.afStorage
        .ref(path)
        .putString(imageData, 'base64', { contentType: 'image/jpeg' });

   // subscribe to download url
      task.downloadURL().subscribe(
        url => {
          //updating profileUrl in the form
          this.profileForm.patchValue({ avatar: url });
      //Doing the update in Firestore
      this.afs.doc(`/profile/${id}`).update(this.profileForm.value);
      });

  }
  Else {
     // just update the profile information
     this.afs.doc(`/profile/${id}`).update(this.profileForm.value);
  }

}

我想避免重复更新代码。有没有更方便的方法来实现这一目标? 也许,如果我在有可用的 downloadUrl 时进行更新(在 2 种情况下)是这样的:

If (userProfilePicture) {
  //upload the picture
  //subscribe to get the download url
}

//AWAIT for the subscribe to return the download URL and when the download URL is available then update
?? How to do this

//update the profile information with the new or existent download URL
await??? this.afs.doc(`/profile/${id}`).update(this.profileForm.value); 

仅供参考 downloadURL() on task 在 5.0 中已贬值,您需要在上传完成后使用 on ref;所以你需要在周围保留对它的引用:

const path = `/profile/${this.profile.id}.jpg`;
const ref = this.afStorage.ref(path);
const task =  ref.putString(imageData, 'base64', { contentType: 'image/jpeg' });

task.snapshotChanges().pipe(
  filter(snap => snap.state === storage.TaskState.SUCCESS)
  switchMap(() => ref.getDownloadURL())
).subscribe(url => {
  ...
})

关于减少重复代码,用update就可以了;因为那只会更新指定的字段。只需将个人资料图片从 profileForm 中删除即可。

// if there's a profile picture to upload, do so
if (userProfilePicture) {
  const path = `/profile/${this.profile.id}.jpg`;
  const ref = this.afStorage.ref(path);
  const task =  ref.putString(imageData, 'base64', { contentType: 'image/jpeg' });

  task.snapshotChanges().pipe(
    filter(snap => snap.state === storage.TaskState.SUCCESS)
    switchMap(() => ref.getDownloadURL())
  ).subscribe(profilePicture => {
    this.afs.doc(`/profile/${id}`).update({profilePicture});
  })
}

// also just update the rest of the profile, update is non-destructive and only overwrites the fields specified
this.afs.doc(`/profile/${id}`).update(this.profileForm.value);