Javascript Async/Wait和promise均未按预期工作

Javascript Async/Wait和promise均未按预期工作,javascript,reactjs,react-redux,firebase-storage,Javascript,Reactjs,React Redux,Firebase Storage,我对javascript非常陌生,在异步/等待和承诺方面遇到了麻烦。 我正在尝试将一组图像异步上传到firebase,以便在下一步获取URL。以下是上传功能 const uploadImage = async (file) => { console.log("starting..."); const storageRef = firebase.storage().ref("forum/" + file[

我对javascript非常陌生,在异步/等待和承诺方面遇到了麻烦。 我正在尝试将一组图像异步上传到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!

您处理承诺的方式有点奇怪,并且具有
newpromise
构造函数反模式。我在这里重写了混乱的部分,我怀疑这将解决您的订购问题:

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";
}

上面的代码片段主要是按照您编写的内容执行的,但是所有不必要的内容都被删除了。应该清楚得多。在继续之前,完全学习承诺和异步/等待是非常值得的。您共享的代码感觉非常反复。

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

  • 从技术上讲,只有在函数内部使用
    await
    时,才应将函数标记为异步,否则在发生错误时可能会出现未定义的行为
  • 由于您没有等待
    获取
    ,因此您需要
    控制台.log(“完成!”)应位于您解析/拒绝的行之后。并非如此,它会立即执行,这就是为什么您看到它们在“启动”之后立即打印的原因。
  • 现在,您通常可以将对
    的所有调用替换为
    等待
    。在JS中,避免“回调地狱”对于代码的清晰性非常重要。有时使用
    newpromise()
    是不可能的,但如果可以避免的话,就应该避免
  • 就像@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);
      }
    };
    

    我以前没听说过你的第一点,但你现在让我好奇了——你能解释一下吗?为什么在没有等待的情况下在异步函数中抛出错误会导致未定义的行为?我认为在这种情况下,执行一般的try..catch是个坏主意。异常的概念是,它们被认为是冒泡到某一点,在那里你可以用它们做一些有用的事情。您正在记录错误(很有用),但无论调用uploadImage什么,都认为它是成功的,因为它基本上得到了成功的响应。