首页 > 解决方案 > 如何使用 async/await 在 Express 中完成这项工作

问题描述

我正在从 MongoDB 服务器中的项目中读取文件名列表,然后检查本地存储中是否存在这些文件名。我正在尝试创建所有匹配文件名的列表,这些文件名同时存在于本地和数据库中,然后在 Express 响应中发送该列表。

这就是我想出的。

app.get('/api/album', (req, res) => {
  let matches = [];

  Album.find({}).then(albums => {
    albums.forEach( (item,  index) => {

      fs.readdir('./static/img/album-art/', (err, files) => {
        files.forEach(file => {
          if (file !== undefined && item.coverUrl !== undefined) {

            if (file == item.coverUrl) {
                matches.push(item.name);
            }
          }
        });
      });
    });
  });

  res.json(matches);
});

但是,响应只包含一个空列表,因为fs.readdir()它是异步的。我想让它保持异步,但我正试图找到一种在完成后发送响应的方法。我不擅长承诺,我知道我可以async/await在这里使用,但我无法让它发挥作用。

标签: javascriptexpresspromise

解决方案


您可以使用对库的内置承诺支持,fs并且还可以避免双重嵌套循环,您可以将文件列表放入 aSet以便更有效地检查每个项目:

const fsp = require('fs').promises;

app.get('/api/album', async (req, res) => {
  let matches = [];

  try {
      let albums = await Album.find({});
      let files = await fsp.readdir('./static/img/album-art/');
      let filesSet = new Set(files);
      let matches = [];
      for (let item of albums) {
          if (filesSet.has(item.coverUrl)) {
              matches.push(item.name);
          }
      }
      res.json(matches);
  } catch(e) {
      console.log(e);
      res.sendStatus(500);
  }
});

根据您的代码,我假设它item.coverUrl实际上只是一个基本文件名mysong.jpg,而不是实际的 URL,因为实际的完全限定 URL 永远不会匹配其中一个文件名。

仅供参考,您不需要任何一项undefined检查。该files数组永远不会包含undefined值,因此即使item.coverUrlis undefined,它也永远不会匹配其中一个文件,因此它会以这种方式照顾自己,因为它永远不会匹配。


推荐阅读