Firebase Web:将多个文件上传到存储,然后下载其URL

时间:2020-02-13 12:03:25

标签: javascript firebase firebase-realtime-database firebase-storage es6-promise

我正在创建一个博客网站,并且正在编写按顺序执行以下操作的代码:
1。存储用户上传的多张照片
2。下载他们的网址
3。将它们保存到实时数据库中。

我写了下面的函数来做#1和#2。基本上,这个想法是将所有网址存储到一个数组中,在本例中为“ urlarray”。

function url_array_get(){
return new Promise(function(resolve,reject){
    let filez=review_photo.files;
    let urlarray=[];
    let user=firebase.auth().currentUser;
    let files=Array.from(filez);
    files.forEach(function(file) {
        let storageRef=firebase.storage().ref('data/'+user.uid+'/posts/'+file.name);
            storageRef.put(file).then(function(snapshot){
                snapshot.ref.getDownloadURL().then(function(url) {
                    urlarray.push(url);
                })
            })
        });
    if (!urlarray){
        reject("oops");
    }
    else {
        resolve(urlarray);
    }
});
}

这是上载功能代码的一部分,该功能会将所有相关数据上载到数据库,包括上面函数中的promise返回的URL数组。 (为了使情况简洁,我省略了其余代码)

        let userpostRef=firebase.database().ref('posts/');
        let newpostRef=userpostRef.push();
                    newpostRef.set({
                        userid: user.uid,
                        post_target: rtarget,
                        post_content:rtext,
                        time: firebase.database.ServerValue.TIMESTAMP
                    }).then(function(){
                            url_array_get().then(function(result){
                            newpostRef.once('value', function(snapshot) {
                                newpostRef.update({
                                    postnum:snapshot.key,
                                    photolink:result
                                })
                        })})}).
            then(function(){
                alert("Upload successful!");
                window.location.href='/'+username;
            })
            .catch(function(error){
                alert("Error!");    
            });               
        }

这是问题所在:代码会将除“ photolink”(应为URL的数组)之外的所有内容写入数据库。
这是我在进行调试时发现的:
-照片存储没有问题。
为每个文件下载-urls,并按预期在执行代码中成功返回urlarray。
可能出了什么问题?我在这里迷路了。任何建议都将非常受欢迎。 非常感谢!

1 个答案:

答案 0 :(得分:1)

每次调用storageRef.put(...)都会启动一个异步操作。现在,您的``不等待这些异步操作完成,而是在填充URLS之前返回URL列表。

最简单的方法是在代码中添加一些简单的日志记录:

function url_array_get(){
  return new Promise(function(resolve,reject){
    let filez=review_photo.files;
    let urlarray=[];
    let user=firebase.auth().currentUser;
    let files=Array.from(filez);
    files.forEach(function(file) {
        console.log("Starting to put file...");
        let storageRef=firebase.storage().ref('data/'+user.uid+'/posts/'+file.name);
            storageRef.put(file).then(function(snapshot){
                console.log("Upload done, getting download URL...");
                snapshot.ref.getDownloadURL().then(function(url) {
                    console.log("Download URL gotten, adding to array...");
                    urlarray.push(url);
                })
            })
        });
    if (!urlarray){
        reject("oops");
    }
    else {
        console.log("Resolving with "+urlarray.length+" download URLs");
        resolve(urlarray);
    }
  });
}

运行此代码时,输​​出将如下所示:

开始放置文件...

开始放置文件...

开始放置文件...

使用0个下载URL解析

上传完成,获取下载URL ...

获得下载URL,并将其添加到数组中...

上传完成,获取下载URL ...

获得下载URL,并将其添加到数组中...

上传完成,获取下载URL ...

获得下载URL,并将其添加到数组中...

这当然不是您想要的顺序,因为您要在向数组添加任何下载URL之前甚至在任何上传完成之前返回数组。


解决方案是(一如往常涉及异步操作)要等到所有操作完成后才能解析/返回。您可以使用Promise.all()最简单地执行以下操作:

function url_array_get(){
    let promises = [];
    let filez=review_photo.files;
    let user=firebase.auth().currentUser;
    let files=Array.from(filez);
    files.forEach(function(file) {
        let storageRef=firebase.storage().ref('data/'+user.uid+'/posts/'+file.name);
        promises.push(
            storageRef.put(file).then(function(snapshot){
                return snapshot.ref.getDownloadURL()
            })
        });
    });
    return Promise.all(promises);
}

或更短:

function url_array_get(){
    let user=firebase.auth().currentUser;
    let ref = firebase.storage().ref('data/'+user.uid+'/posts/');
    let files=Array.from(review_photo.files);
    let promises = files.map(function(file) {
        return ref.child(file.name).put(file).then(function(snapshot){
            return snapshot.ref.getDownloadURL()
        })
    });
    return Promise.all(promises);
}