Firebase 存储中的异步/等待(上传文件后等待获取 URL)

时间:2021-02-08 08:29:12

标签: javascript vue.js async-await firebase-storage

我在我的 Vue 项目中使用 Firestore,我正在开发一项允许用户上传图片的功能,但是我面临以下问题:

我有一个“newMarker”占位符对象,用户可以在其中填写信息,一旦用户确认输入,该对象就会保存到数据库中。当用户确认我想要的输入时:

  1. 将图片保存在 Firebase 存储中
  2. 获取为该文件生成的 URL
  3. 将 URL 添加到 newMarker 对象
  4. 然后将包含 imgURL 的 newMarker 对象推送到数据库

但是我不知道如何让代码等待上传状态完成后立即运行的回调函数(在uploadIMG函数中,'uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED',最后一个回调函数)并返回一个带有url的promise。不管我做什么,这个回调函数最后执行。

当用户确认输入时,会执行 saveNewMarker() 并运行以下代码:

我的代码:

    async saveNewMarker() {
        await this.uploadImg();
        console.log('Image upload finished! Pushing new marker to db')

        await db.collection(this.user.email).add({
            position: this.newMarker.position,
            type: this.newMarker.type,
            location: this.newMarker.location,
            imgURL: this.newMarker.imgURL
        })
        .then((marker) => {
            console.log('marker added to database')
            this.newMarker.id = marker.id
        })
    },
    async uploadImg(){
        console.log('Uploading image ...')
        const storageRef = firebase.storage().ref();
        const uploadTask = storageRef.child('user-uploads/images/' + this.file.name).put(this.name)

        uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, 
            (snapshot) => {
                const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
                console.log('Upload is ' + progress + '% done');
            }, 
            (error) => {
                console.log(error)
            }, 
            async () => {
                const imgURL = await uploadTask.snapshot.ref.getDownloadURL()
                console.log('uploaded image: ' + imgURL)
                this.newMarker.imgURL = imgURL
            }
        );
    },

输出:

Uploading image ...
Upload is NaN% done
Image upload finished! Pushing new marker to db
marker added to database
uploaded image: https://firebasestorage.googleapis.com/v0/b/....

预期输出:

Uploading image ...
Upload is NaN% done
uploaded image: https://firebasestorage.googleapis.com/v0/b/....
Image upload finished! Pushing new marker to db
marker added to database

2 个答案:

答案 0 :(得分:1)

您必须将代码封装在 uploadImg 中,并在图片上传完成后解决它。将 uploadImg 重构为如下所示的内容应该可以:

async uploadImg() {
  return new Promise((resolve, reject) => {
    console.log("Uploading image ...");
    const storageRef = firebase.storage().ref();
    const uploadTask = storageRef.child("user-uploads/images/" + this.file.name).put(this.name);

    uploadTask.on(
      firebase.storage.TaskEvent.STATE_CHANGED,
      (snapshot) => {
        const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        console.log("Upload is " + progress + "% done");
      },
      (error) => {
        console.log(error);
        reject(error);
      },
      async () => {
        const imgURL = await uploadTask.snapshot.ref.getDownloadURL();
        console.log("uploaded image: " + imgURL);
        this.newMarker.imgURL = imgURL;
        resolve();
      }
    );
  });
},

答案 1 :(得分:1)

这不是 async/await 的用途,我建议改用 Promises,就像这样:

function saveNewMarker() {
    // Call uploadImg as a Promise and wait for the result
    this.uploadImg()
        .then((imgURL) => {
            console.log('Image upload finished! Pushing new marker to db');

            db.collection(this.user.email).add({
                position: this.newMarker.position,
                type: this.newMarker.type,
                location: this.newMarker.location,
                imgURL: this.newMarker.imgURL
            })
                .then((marker) => {
                    console.log('marker added to database');
                    this.newMarker.id = marker.id;
                })
        }).catch((error) => {
        //Do something
        });
};

function uploadImg() {
    // Return a promise that will either resolve or emit an error
    return new Promise((resolve, reject) => {
        console.log('Uploading image ...');
        const storageRef = firebase.storage().ref();
        const uploadTask = storageRef.child('user-uploads/images/' + this.file.name).put(this.name);

        uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
            (snapshot) => {
                const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
                console.log('Upload is ' + progress + '% done');
            },
            (error) => {
                console.log(error);
                // An error occurred so inform the caller
                reject(error);
            },
            async () => {
                const imgURL = await uploadTask.snapshot.ref.getDownloadURL();
                console.log('uploaded image: ' + imgURL);
                this.newMarker.imgURL = imgURL;

                // We 'awaited' the imgURL, now resolve this Promise
                resolve(imgURL);
            }
        );
    });
};

并记住您的分号以避免意外行为或错误。