如何将多个文件上传到Firebase?

时间:2017-01-16 09:48:40

标签: javascript firebase firebase-storage

有没有办法将多个文件上传到Firebase存储空间。它可以在单次尝试中上传单个文件,如下所示。

fileButton.addEventListener('change', function(e){ 
//Get file
var file = e.target.files[0];

//Create storage reference
var storageRef = firebase.storage().ref(DirectryPath+"/"+file.name);

//Upload file
var task = storageRef.put(file);

//Update progress bar
  task.on('state_changed',
    function progress(snapshot){

        var percentage = snapshot.bytesTransferred / snapshot.totalBytes * 100;
        uploader.value = percentage;
    },
    function error(err){

    },
    function complete(){
        var downloadURL = task.snapshot.downloadURL;

    }
  );

});

如何将多个文件上传到Firebase存储空间。

10 个答案:

答案 0 :(得分:15)

我找到了上述问题的解决方案,我想把它放在这里因为它对任何人都有用。

//Listen for file selection
fileButton.addEventListener('change', function(e){ 
    //Get files
    for (var i = 0; i < e.target.files.length; i++) {
        var imageFile = e.target.files[i];

        uploadImageAsPromise(imageFile);
    }
});

//Handle waiting to upload each file using promise
function uploadImageAsPromise (imageFile) {
    return new Promise(function (resolve, reject) {
        var storageRef = firebase.storage().ref(fullDirectory+"/"+imageFile.name);

        //Upload file
        var task = storageRef.put(imageFile);

        //Update progress bar
        task.on('state_changed',
            function progress(snapshot){
                var percentage = snapshot.bytesTransferred / snapshot.totalBytes * 100;
                uploader.value = percentage;
            },
            function error(err){

            },
            function complete(){
                var downloadURL = task.snapshot.downloadURL;
            }
        );
    });
}

答案 1 :(得分:7)

Firebase存储使用Promise,因此您可以使用Promise来实现它。

以下是涉及此主题的firebase博客文章: Keeping our Promises (and Callbacks)

给Promise.all()一个“承诺数组”

Promise.all(
  // Array of "Promises"
  myItems.map(item => putStorageItem(item))
)
.then((url) => {
  console.log(`All success`)
})
.catch((error) => {
  console.log(`Some failed: `, error.message)
});

上传每个文件并返回Promise

putStorageItem(item) {
  // the return value will be a Promise
  return firebase.storage().ref("YourPath").put("YourFile")
  .then((snapshot) => {
    console.log('One success:', item)
  }).catch((error) => {
    console.log('One failed:', item, error.message)
  });
}

YourPathYourFile可以与myItems数组一起携带(因此item对象)。

为了便于阅读,我在这里省略了它们,但你得到了这个概念。

答案 2 :(得分:5)

我相信有一个更简单的解决方案:

{{1}}

答案 3 :(得分:2)

这是标记答案的修改版本,适用于希望在每次其他上传开始之前等待每次上传完成的用户。

按照标有答案的约定,诺言没有得到解决或拒绝,因此,当上传从循环开始时,一切都将开始,第一个文件,第二个文件.....

每20mb有3个上传文件。该循环将几乎同时调用上载函数,从而使它们几乎同时运行。

此答案使用async/await来处理promises

fileButton.addEventListener('change', async function(e){ 
    //Get files
    for (var i = 0; i < e.target.files.length; i++) {
        var imageFile = e.target.files[i];
        await uploadImageAsPromise(imageFile).then((res)=>{
         console.log(res);
          });
    }
});

//Handle waiting to upload each file using promise
async function uploadImageAsPromise (imageFile) {
    return new Promise(function (resolve, reject) {
        var storageRef = firebase.storage().ref(fullDirectory+"/"+imageFile.name);
        var task = storageRef.put(imageFile);

        //Update progress bar
        task.on('state_changed',
            function progress(snapshot){
                var percentage = snapshot.bytesTransferred / snapshot.totalBytes * 
                     100;
            },
            function error(err){
                console.log(err);
                reject(err);
            },
            function complete(){
                var downloadURL = task.snapshot.downloadURL;
                resolve(downloadURL);
            }
        );
    });
}

答案 4 :(得分:1)

        let ad_images=["file:///data/user/0/..../IMG-20181216-WA00001.jpg",
                       "file:///data/user/0/..../IMG-20181216-WA00002.jpg",
                       "file:///data/user/0/..../IMG-20181216-WA00003.jpg"];
        let firebase_images=[];

        const ref = firebase.firestore().collection('ads').doc(newRecord.id);
        putStorageItem = (url,index,ext) => {
            return firebase.storage().ref('YOURFOLDER/'+ index +'.'+ext ).putFile(url)
            .then((snapshot) => {
                console.log(snapshot)
                firebase_images[index] = snapshot.downloadURL;              
                //OR
                //firebase_images.push(snapshot.downloadURL);
            }).catch((error) => {
                console.log('One failed:', error.message)
            });
        }

        Promise.all(
            ad_images.map( async (item,index) => {
                let ext = item.split('/').pop().split(".").pop();
                console.log(newRecord.id, item, index, ext);
                await putStorageItem(newRecord.id, item, index, ext);
            })
        )
        .then((url) => {
            console.log(`All success`);
            console.log(firebase_images);
        })
          .catch((error) => {
            console.log(`Some failed: `, error.message)
        });

答案 5 :(得分:1)

@isuru,上传问题的人下面提供了一个很好的解决方案。但是,一些firebase功能已更新。因此,我刚刚使用Firebase中的新更新更新了解决方案。

  //Firebase Storage Reference
  const storageRef = firebase.storage().ref();

  //Upload Image Function returns a promise  
  async function uploadImageAsPromise(imageFile) {
    return new Promise(function (resolve, reject) {
      const task = storageRef.child(imageFile.name).put(imageFile);

      task.on(
        "state_changed",
        function progress(snapshot) {
          const percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        },

        function error(err) {
          reject(err);
        },

        async function complete() {
          //The getDownloadURL returns a promise and it is resolved to get the image url.
          const imageURL = await task.snapshot.ref.getDownloadURL();
          resolve(imageURL);
        }
      );
    });
  }
  
  //Handling the files
  fileButton.addEventListener('change', function(e){ 
    const promises = [];
    for(const file of e.target.files){//Instead of e.target.files, you could also have your files variable
        promises.push(uploadImageAsPromise(file))
    }
    
    //The Promise.all() will stop the execution, until all of the promises are resolved.
    Promise.all(promises).then((fileURLS)=>{
        //Once all the promises are resolved, you will get the urls in a array.
        console.log(fileURLS)
    })
  });

答案 6 :(得分:0)

我们可以像这样组合多个承诺

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});

我们可以像这样实现连锁承诺

return myFirstPromise.then( (returnFromFirst) => {
    //Do something
    return secondPromise();
}).then( (returnFromSecond) => {
    //Do something
    return thirdPromise();
}).then( (returnFromThird) => {
    //All Done
}).catch( (e) =>{}
    console.error("SOMETHING WENT WRONG!!!");
);

想法是将上传文件的承诺与 Promise.all 结合在一起,并将它们链接在一起,以在每次上传后获得下载URL。

      Promise.all(
            //Array.map creates a new array with the results 
          // of calling a function for every array element. 
          //In this case Array of "Promises"
            this.state.filesToUpload.map(item => 
             this.uploadFileAsPromise(item))
          )
            .then(url => {
              console.log(`All success`);

              //Handle Success all image upload

            })
            .catch(error => {
              console.log(`Some failed: `, error.message);

              //Handle Failure some/all image upload failed             
            });


  //return a promise which upload file & get download URL 
  uploadFileAsPromise(imageFile) {
        // the return value will be a Promise
        return storageRef
          .child("images/users/" + imageFile.name)
          .put(imageFile.file) 
          .then(snapshot => {
            console.log("Uploaded File:", imageFile.name);
            return snapshot.ref.getDownloadURL().then(downloadURL => {
              //promise inside promise to get donloadable URL
              console.log("File available at", downloadURL);
              );
            });
          })
          .catch(error => {
            console.log("Upload failed:", imageFile.name, error.message);
          });
      }

答案 7 :(得分:0)

所有的承诺很快就会变得混乱,为什么不使用 async await 代替?

这里,我有一个功能,可以跟踪从输入/文件控件中选择要上传的所有图像:

let images =[];
let imagePaths=[];

const trackFiles =(e)=>{
    images =[];
    imagePaths =[];
    for (var i = 0; i < e.target.files.length; i++) {
        images.push(e.target.files[i]);
    }
}

我还有另一个功能,该功能将由一个按钮触发,当用户准备好进行实际上传时,该按钮将被单击:

const uploadFiles =()=>{
    const storageRef = storage.ref();

    images.map(async img =>{
        let fileRef = storageRef.child(img.name);
        await fileRef.put(img);
        const singleImgPath = await fileRef.getDownloadURL();
        imagePaths.push(singleImgPath);

        if(imagePaths.length == images.length){
            console.log("got all paths here now: ", imagePaths);
        }
    })
}

基本上,我们遍历每个图像并执行上传,然后将图像路径逐个推入一个单独的imagePaths数组中,因为它们各自以自己的步调完成,然后我就在掌握了所有路径后抓取了所有路径通过比较图像的长度及其最终路径来完成。

答案 8 :(得分:0)

使用 rxjs 的 switchMap 和 combineLatest 轻松实现 Angular fire

答案 9 :(得分:0)

上传文件并获取下载地址

   export const handleFileUploadOnFirebaseStorage = async (bucketName, file) => {
      // 1. If no file, return
      if (file === "") return "";

      // 2. Put the file into bucketName
      const uploadTask = await storage.ref(`/${bucketName}/${file.name}`).put(file);
      
      // 3. Get download URL and return it as 
      return uploadTask.ref.getDownloadURL().then((fileURL) => fileURL);
   };

上传多个文件并获取下载地址

export const handleFilesUploadOnFirebaseStorage = async (bucketName, files) => {
    // 1. If no file, return
    if (files.length === 0) return [];

    // 2. Create an array to store all download URLs
    let fileUrls = [];

    // 3. Loop over all the files
    for (var i = 0; i < files.length; i++) {
        // 3A. Get a file to upload
        const file = files[i];

        // 3B. handleFileUploadOnFirebaseStorage function is in above section
        const downloadFileResponse = await handleFileUploadOnFirebaseStorage(bucketName, file);
        
        // 3C. Push the download url to URLs array
        fileUrls.push(downloadFileResponse);
    }

    return fileUrls;
};