为什么我的 for...of 循环返回空数组,Javascript 节点

Why is my for...of loop returning empty array, Javascript Node

我正在尝试通过 express/node 上传从前端 formData 发送到 Firebase 存储的三张 post 图片。我喜欢 return 对象数组的函数,每个对象都有图像名称和 publicUrl,然后我可以将其保存在 Firestore 中相应的 Post 文档中。

下面当前代码的问题在于它return是一个空数组[]。尽管 urls.push() 方法中的日志显示了正确的数组,但我只是不知道如何从以下 .then() 方法访问它。

感谢您的帮助!

    router.post(
      "/",
      auth,
      uploader.fields([
        { name: "cardImage", maxCount: 1 },
        { name: "postImageOne", maxCount: 1 },
        { name: "postImageTwo", maxCount: 1 },
      ]),
    async (req, res, next) => {
    try {
      const { title, caption, content } = req.body;
      const { uid } = req.user;
      //add images to storage

      const imagesWriteFunction = async () => {
        var urls = [];

        for (const [key, value] of Object.entries(req.files)) {
          console.log(`---Starting upload process for ${key}---`);
          const blob = bucket.file(`${value[0].originalname}`);

          const blobWriter = blob.createWriteStream({
            metadata: {
              contentType: value[0].mimetype,
            },
          });

          blobWriter.on("error", (err) => next(err));
          blobWriter.on("finish", () => {
            console.log("---Assemblying Public URL---", blob.name);
            const publicUrl = `https://firebasestorage.googleapis.com/v0/b/${
              bucket.name
            }/ImagePosts/o/${encodeURI(blob.name)}?alt=media`;
            urls.push(`{ ${key}: ${publicUrl} }`);
            console.log("urls push log", urls);
          });
          console.log("urls .on() log", urls);

          blobWriter.write(value[0].buffer);
          blobWriter.end();
        }
        return urls;
      };

      imagesWriteFunction().then( (urls) => {
        console.log("iamgeUrls log", urls);
//I a want to access urls here so I can send with other form data to Post doc in firestore.
      });
      res.status(200).send(newPostData);
    } catch (err) {
      console.log("createPost error", err);
    }
  }
);

console.log

---Starting upload process for cardImage---
Sending image cardImage: [object Object] to Storage
---Starting upload process for postImageOne---
Sending image postImageOne: [object Object] to Storage
---Starting upload process for postImageTwo---
Sending image postImageTwo: [object Object] to Storage
urls log []
imagesWriteFunction urls log []
---newPostRes--- zt0OkMbLg2osceAtf3Vo
---Successfully added to user posts array--- WriteResult {
  _writeTime: Timestamp { _seconds: 1622789685, _nanoseconds: 86941000 }
}
---Assemblying Public URL--- woodywoodpecker.png
urls push log [
  '{ postImageOne: https://firebasestorage.googleapis.com/v0/b/devport-express-backend.appspot.com/ImagePosts/o/woodywoodpecker.png?alt=media }'
]
---Assemblying Public URL--- images.jpg
urls push log [
  '{ postImageOne: https://firebasestorage.googleapis.com/v0/b/devport-express-backend.appspot.com/ImagePosts/o/woodywoodpecker.png?alt=media }',
  '{ postImageTwo: https://firebasestorage.googleapis.com/v0/b/devport-express-backend.appspot.com/ImagePosts/o/images.jpg?alt=media }'
]
---Assemblying Public URL--- johnnybravo.jpg
urls push log [
  '{ postImageOne: https://firebasestorage.googleapis.com/v0/b/devport-express-backend.appspot.com/ImagePosts/o/woodywoodpecker.png?alt=media }',
  '{ postImageTwo: https://firebasestorage.googleapis.com/v0/b/devport-express-backend.appspot.com/ImagePosts/o/images.jpg?alt=media }',
  '{ cardImage: https://firebasestorage.googleapis.com/v0/b/devport-express-backend.appspot.com/ImagePosts/o/johnnybravo.jpg?alt=media }'
]
[nodemon] restarting due to changes...
[nodemon] starting `node index index.js`
Server started on port: 5000

您的 for ... of 循环没有返回任何内容,因为 blobWriter 在填充您的 urls 数组之前正在等待事件“完成”,因此您在操作完成之前离开该函数,最后什么也得不到。正如您在日志中清楚地看到的那样,首先您得到了 urls log [] imagesWriteFunction urls log [],然后当事件“完成”被触发时,您得到了 blobWrite 的实际结果。

为防止这种正常行为,您可以使用 Promise 来“承诺”此调用并能够等待它,这里是一种方法 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise):

const blobWriterAsync = (value, key) =>
  new Promise((resolve, reject) => {
    const blob = bucket.file(`${value[0].originalname}`);

    const blobWriter = blob.createWriteStream({
      metadata: {
        contentType: value[0].mimetype
      }
    });

    blobWriter.on('error', (err) => reject(err)); // <==== REJECT so you can catch the error later
    blobWriter.on('finish', () => {
      console.log('---Assemblying Public URL---', blob.name);
      const publicUrl = `https://firebasestorage.googleapis.com/v0/b/${bucket.name}/ImagePosts/o/${encodeURI(blob.name)}?alt=media`;
      resolve(`{ ${key}: ${publicUrl} }`) // <== RESOLVE so you can await for it or use .then
    });

    blobWriter.write(value[0].buffer);
    blobWriter.end();
  });

const imagesWriteFunction = async () => {
  var urls = [];

  for (const [key, value] of Object.entries(req.files)) {
    try {
      const url = await blobWriterAsync(value, key)

      urls.push(url);
    } catch (err) {
      console.log("do something with err");
    }
  }
  return urls;
};