【问题标题】:node.js ignores awaitZip building with expressnode.js 使用 express 忽略 awaitZip 构建
【发布时间】:2018-09-22 14:17:29
【问题描述】:

我想用 mongoose 从我们的 mongodb 数据库中的 gridfs 获取图标 PNGS。然后应该压缩这些图标并在特定路线上提供服务。

我目前的代码如下:

var zip = require("node-native-zip");
async function getZipFile() {
    //get the events out of the DB
    db.Category.find({}).populate('icons.file').exec(async function (err, cats) {
        if (err) {
            //oh oh something went wrong, better pass the error along
            return ({
                    "success": "false",
                    message: err
                });
        }
        else {
            //all good, build the message and return
            try {
                const result = await buildZip(cats);
                return ({
                    "success": "true",
                    message: result
                });
            }
            catch (err) {
                console.log("ZIP Build Failed")
            }
        }
    });
}
async function buildZip(cats) {
    let archive = new zip();
    for (let i = 0; i < cats.length; i++) {
        cats[i].icons.forEach(function (icon) {
            if (icon.size === "3x") {
                db.Attachment.readById(icon.file._id, function (err, buffer) {
                    if (err)
                        return;
                    archive.add(cats[i]._id + ".png", buffer);
                });
            }
        });
        //return when everything is done
        if (i === cats.length - 1) {
            return archive.toBuffer();
        }
    }
}
module.exports =
    {
        run: getZipFile
    };

我不想在运行前构建 zip,因为我想根据类别 ID 重命名图标。我尝试使用 async/await 结构,但我的回调在 zip 文件的构建开始之前就被返回了。

我正在调用函数

    case 'categoryZip':
        categoryHelper.getZipFile.run().then((result) => {
            callback(result);
        });
        break;

这应该(据我理解)在压缩完成时触发回调,但我认为我在这里遗漏了一些重要的东西。

【问题讨论】:

  • 基于回调的 API 不能在 async 函数中“正常工作”。您必须将它们转换为承诺。这里的async 函数不知道您的db 方法中的回调,也不会await 它们。
  • @PatrickRoberts 所以你说我应该将db.Category.find({}).populate('icons.file').exec 转换为基于承诺的函数,等待它,然后继续我的异步 zip 构建?
  • 是的,那个和db.Attachment.readById(),虽然那个可能不能在forEach()中工作,但是你可以使用for (const icon of cats[i].icons)

标签: javascript node.js express mongoose async-await


【解决方案1】:

我将您的两个回调方法都包装到了 Promise 中,并且还使用 Promise.all() 并行等待了您的双 for 回调循环,因为它们不相互依赖,我认为它们不需要特别压缩文件中的顺序:

async function getZipFile() {
  //get the events out of the DB
  return new Promise((resolve, reject) => {
    db.Category.find({}).populate('icons.file').exec(async function(err, cats) {
      if (err) {
        //oh oh something went wrong, better pass the error along
        reject({
          success: false,
          message: err
        });
      } else {
        //all good, build the message and return
        try {
          const result = await buildZip(cats);

          resolve({
            success: true,
            message: result
          });
        } catch (err) {
          console.log("ZIP Build Failed")
          reject({
            success: false,
            message: err
          });
        }
      }
    });
  });
}

async function buildZip(cats) {
  let archive = new zip();

  await Promise.all(
    cats.map(cat => Promise.all(cat.icons
      .filter(icon => icon.size === '3x')
      .map(icon => new Promise((resolve, reject) => {
        db.Attachment.readById(icon.file._id, function(err, buffer) {
          if (err) return reject(err);
          archive.add(cat._id + ".png", buffer);
          resolve();
        });
      }))
    ))
  );

  return archive.toBuffer()
}

【讨论】:

  • 神圣!非常感谢,您的答案和代码运行良好。这太神奇了,从来没有想过这个承诺结构!
  • 很高兴我能帮上忙
猜你喜欢
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
  • 2014-06-17
  • 2018-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多