我正在开发一个以firebase为后端的烹饪android应用程序,我需要在firebase存储中上传食谱的多个图像,然后将downloadurl存储到firebase数据库中。
我设法将文件上传到Firebase,但是我在获取这些文件的downloadUrl时遇到了一些麻烦。 我创建了一个承诺数组来上传文件,并且我创建了另一个数组来存储每个文件的URL,这些文件在完成上传任务后会得到。
这是我的代码
var promises = [];
for (var i=0 ;i< prepaImages.length;i++)
{
//alert(prepaImages[i].name);
var storageRef = firebase.storage().ref("receipes"+"/"+category+"/"+title+"/"+uploadTime+prepaImages[i].name );
var uploadTask = storageRef.put(prepaImages[i]);
promises.push(uploadTask);
uploadTask.on('state_changed', snapshot => {
var percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
$("#prepaImageUploadprogress").html(Math.round(percentage)+"%");
$("#prepaImageUploadprogress").attr("style", "width:"+percentage+"%");
}, error => { alert(error) }, () => {
uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => {
//prepaImagesUrl+="+"+downloadURL;
prepaImagesUrl.push(downloadURL);
});
});
问题是我得到的是上传文件数的长度减一的数组(其长度应等于上传文件数的长度),并且具有相同的值(相同的下载网址) 。任何帮助将不胜感激 谢谢。
答案 0 :(得分:2)
我认为问题在于承诺。我建议您使用Promise.all
并等待。因此,您的代码将更加可靠。这是我上传多个文件(适合您的变量名)的解决方案:
const array = Array.from({ length: prepaImages.length }, (value, index) => index);
const uploadedImages = await Promise.all(array.map(async index => {
const image = prepaImages[index];
const metadata = { contentType: image.type };
const storageRef = firebase.storage().ref(`receipes/${category}/${title}/${uploadTime}${prepaImages[i].name}`);
const uploadTask = storageRef.put(image, metadata);
const url = await new Promise((resolve, reject) => {
uploadTask.on('state_changed', snapshot => {
const percentage = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
$('#prepaImageUploadprogress').html(`${Math.round(percentage)}%`);
$('#prepaImageUploadprogress').attr('style', `width: ${percentage}%`);
}, error => reject(error),
async () => {
const downloadUrl = await uploadTask.snapshot.ref.getDownloadURL();
resolve(downloadUrl);
});
});
return { name: image.name, url };
}));
uploadedImages
将包含带有图像名称和下载URL的数组。您当然可以不用等待,但是我更喜欢这种方式。
更新:
这是我自己的代码(没有错误处理)来实现这一目标,同时,我还需要提及的是,我将其与react,redux一起使用,并将firebase,firestore包装器用于redux redux-firestore
和react-redux-firebase
但这只是包装器:
export const addNewWork = work => async (dispatch, getState, { getFirebase, getFirestore }) => {
const { files, ...restWork } = work;
const firebase = getFirebase();
const firestore = getFirestore();
const storageRef = firebase.storage().ref();
const array = Array.from({ length: files.length }, (value, index) => index);
const uploadedFiles = await Promise.all(array.map(async index => {
const file = files[index];
const metadata = { contentType: file.type };
const uploadTask = storageRef.child(`works/${file.name}`).put(file, metadata);
const url = await new Promise((resolve, reject) => {
uploadTask.on('state_changed', () => {}, error => reject(error), async () => {
const downloadUrl = await uploadTask.snapshot.ref.getDownloadURL();
resolve(downloadUrl);
});
});
return { name: file.name, url };
}));
await firestore.collection('works').add({
...restWork,
image: uploadedFiles[0], // Use only one image for the clean example
createdAt: new Date()
});
});