#javascript #reactjs #react-redux #firebase-storage
# #javascript #reactjs #реагировать-redux #firebase-хранилище
Вопрос:
Я довольно новичок в javascript, и у меня возникли проблемы с async / await и promises. Я пытаюсь асинхронно загрузить массив изображений в firebase, чтобы вернуть URL-адреса для следующего шага. Ниже приведена функция загрузки.
const uploadImage = async (file) => {
console.log("starting...");
const storageRef = firebase.storage().ref("forum/" file[1]);
return new Promise((resolve, reject) => {
fetch(file[0])
.then(async (res) => {
console.log("res to blob");
return await res.blob();
})
.then(async (blob) => {
blob.name = file[1];
console.log("Starting to put file...", blob);
await storageRef.put(blob).then(async () => {
const url = await storageRef.getDownloadURL();
urlArray.push(url);
console.log(url);
!url ? resolve("got url!") : reject("it broke");
});
});
console.log("done!");
});
};
const uploadArray = async (imageArray) => {
return await Promise.all(
imageArray.map((image) => uploadImage(image))
);
};
uploadArray(project.images).then((urls) => {
urls.forEach((element) => {
console.log(element);
});
});
Это консоль при каждом вызове uploadArray() .
starting...
done!
starting...
done!
res to blob
Starting to put file... Blob {name: "IMG_3851.JPG", size: 1417851, type: "image/jpeg"}
Starting to put file... Blob {name: "IMG_3852.JPG", size: 2391056, type: "image/png"}
https://firebasestorage.googleapis.com/... (Link to firebase)
Uncaught (in promise) it broke```
https://firebasestorage.googleapis.com/... (Link to firebase)
Но я хочу, чтобы консоль регистрировала операторы в этом порядке.
starting
res to blob
Starting to put file... Blob {name: "IMG_3851.JPG", size: 1417851, type: "image/jpeg"}
https://firebasestorage.googleapis.com/... (Link to firebase)
done!
starting
res to blob
Starting to put file... Blob {name: "IMG_3852.JPG", size: 2391056, type: "image/png"}
https://firebasestorage.googleapis.com/... (Link to firebase)
done!
Ответ №1:
Способ обработки обещаний немного странный и имеет new Promise
анти-шаблон конструктора. Я переписал здесь беспорядочные части, и я подозреваю, что это решит вашу проблему с заказом:
const uploadImage = async (file) => {
console.log("starting...");
const storageRef = firebase.storage().ref("forum/" file[1]);
const res = await fetch(file[0]);
const blob = await res.blob();
blob.name = file[1];
console.log("Starting to put file...", blob);
await storageRef.put(blob);
const url = await storageRef.getDownloadURL();
urlArray.push(url);
console.log(url);
if (url) {
return "got url";
}
throw "it broke";
}
Приведенный выше фрагмент в основном выполняет то, что вы написали, но все ненужное затем удаляется. Это должно быть намного понятнее. Очень полезно полностью изучить promises и async / await, прежде чем продолжить. Код, которым вы поделились, выглядит как метод проб и ошибок.
Ответ №2:
Пара лакомых кусочков о JS и async / await:
- Технически функции должны быть помечены как асинхронные, только если они используются
await
внутри него — в противном случае вы можете получить неопределенное поведение при возникновении ошибок - Поскольку вы не ожидаете
fetch
, вамconsole.log("done!");
следует перейти к строке, в которой вы разрешаете / отклоняете. Это не значит, что оно выполняется немедленно, поэтому вы видите их напечатанными сразу после"starting"
- В настоящее время вы обычно можете заменить все вызовы на
.then
наawait
. Избегать «ада обратного вызова» очень важно в JS, когда дело доходит до ясности кода. Иногда невозможно обойти использованиеnew Promise()
, но если этого можно избежать, это должно быть
Как и в ответе @Evert, удаление обратных вызовов и использование правильных ожиданий, скорее всего, устранит ваши проблемы с заказом.
Также было бы неплохо добавить try catch для всех вызовов API, чтобы вы не получили необработанное исключение promise. Его можно добавить в uploadImage
метод или туда, куда вы вызываете Promise.all
, в зависимости от того, что лучше всего подходит для вашего варианта использования.
const uploadImage = async (file) => {
try {
console.log("starting...");
const storageRef = firebase.storage().ref("forum/" file[1]);
const res = await fetch(file[0]);
console.log("res to blob");
const blob = await res.blob();
blob.name = file[1];
console.log("Starting to put file...", blob);
await storageRef.put(blob);
const url = await storageRef.getDownloadURL();
urlArray.push(url);
console.log(url);
if (!url) throw new Error("it broke");
console.log("done!");
} catch (err) {
console.error(err);
}
};
Комментарии:
1. Я раньше не слышал о вашем первом пункте, но теперь мне стало любопытно — не могли бы вы немного рассказать об этом? Почему ошибка в асинхронной функции без await вызывает неопределенное поведение?
2. Я думаю, что делать общую попытку ..catch в этом случае плохая идея. Идея исключений заключается в том, что они должны всплывать до такой степени, что вы можете сделать с ними что-то полезное. Вы регистрируете ошибку (полезно), но все, что вызывает uploadImage, по-прежнему считает, что оно было успешным, потому что оно в основном получило успешный ответ.