Async/await和promise都没有按预期工作



我对javascript还很陌生,在async/await和promise方面遇到了问题。我正在尝试将一组图像异步上传到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!

处理promise的方式有点奇怪,并且具有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";
}

上面的片段大部分都是你写的,但所有不必要的都被删除了。它应该清楚得多。在继续之前,非常值得充分学习promise和async/await。你分享的代码让人感觉非常反复。

关于JS和async/await:的一些花絮

  1. 从技术上讲,只有当函数内部使用await时,才应将其标记为async,否则在发生错误时可能会得到未定义的行为
  2. 由于您没有等待fetch,因此您的console.log("done!");应该在您解析/拒绝的行之后。并不是说它会立即执行,这就是为什么你看到它们在"starting"之后立即打印出来的原因
  3. 现在,您通常可以用await替换对.then的所有调用。避免";回调地狱";当涉及到代码清晰度时,在JS中是非常重要的。有时使用new Promise()是不可能的,但如果可以避免,应该

就像@Evert的回答一样,删除回调并使用适当的等待可能会解决您的订购问题。

在所有API调用周围添加一个try-catch也是一个好主意,这样您就不会得到未处理的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);
}
};

相关内容

  • 没有找到相关文章

最新更新