#javascript #firebase #firebase-storage
#javascript #firebase #firebase-хранилище
Вопрос:
я работаю над кулинарным приложением для Android, где firebase является серверной частью, мне нужно загрузить несколько изображений рецепта в firebase stoarge, а затем сохранить 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);
});
});
проблема в том, что я получаю массив длиной в количество загруженных файлов минус один (длина должна быть равна количеству загруженных файлов), и он имеет то же значение (тот же downloadurl)
. любая помощь будет оценена
Спасибо.
Ответ №1:
Я думаю, проблема в обещаниях. Я предлагаю вам использовать 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-адресами для загрузки. Конечно, вы можете сделать это без await, но я предпочитаю этот способ.
ОБНОВЛЕНИЕ: Вот мой собственный код (без обработки ошибок) для достижения этой цели, также я должен упомянуть, что я использую это с 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()
});
});
Комментарии:
1. спасибо за ответ. но, похоже, это тоже не работает, оно возвращает пустой массив после «return { name: file.name, url }; » я пытался сохранить массив в базе данных, но это не работает, он выдает пустой массив
2. Изображения поступают из поля ввода? Этот точно такой же код отлично работает с одним из моих проектов :
3. Возможно, проверьте еще раз код, я допустил несколько ошибок с именами переменных, когда переименовал их в соответствии с вашим вариантом использования :
4. да, да, я уже исправил опечатки и имена переменных, но это не сработало, для загрузки в базу данных я должен сделать это вне «await Promise.all (array.map(async index => {» или внутри него, для меня это, похоже, не сработало в обоих случаях
5. если возможно, не могли бы вы дать мне рабочий код, который у вас есть, может быть, я мог бы понять, чего мне не хватает, пожалуйста