首页 > 解决方案 > 将回调代码重构为 async / await

问题描述

我有一个 node.js /(基于 express)loopback.js 应用程序,带有一个使用 HtmlToPDF 生成 PDF 的 PDF 服务。

一些代码:

服务/pdf.js

exports.PDF = function(options, cb) {
  // ...
  var htmlToPDF = new HTMLToPDF({
    // ... options
  });

  function sendBackFile(outputPath, cb) {
    fs.readFile(outputPath, function (err, data) {
      if (err) {cb(err)}
      var contentDisposition = 'attachment; filename=' + filename + '.pdf';
      cb(null, data, 'application/pdf', contentDisposition, 'SAMEORIGIN');
    })
  }
  // start / stop Xvfb code ...
  htmlToPDF.build(function (err) {
    if (err) {cb(err)};
    // read the file and send it back
    sendBackFile(outputPath, cb)
  });
}

对于不同类型的 PDF,我有不同的模板。(对于每种类型的不同名称、输出路径、模板等)

exports.invetory = function(html, cb) {
  exports.PDF({
    html: html
  }, cb);
}

这是一个示例,我如何使用代码中的服务。

模型/inventory.js

  Inventory.pdf = (id, next) => {
    pdf.inventory('yo', next);
  }

分解

  1. PDF服务导入代码,调用库存模板
  2. 库存模板调用 PDF 服务
  3. PDF 服务启动一个 htmlToPDF 实例,创建一个 PDF 并保存为文件。
  4. 从磁盘读取文件,然后 API 将其发回。

问题

我尝试使我的Inventory.pdf函数具有异步/等待意识。但如果我这样做

  Inventory.pdf = async (id, next) => {
    return await pdf.inventory('yo', next);
  }

接下来,(回调函数)将是undefined,没关系,但是我应该如何更改 PDF 服务,以使其与异步调用和旧回调方式一起工作。(我在代码中有很多旧模板函数)。任何建议都非常受欢迎。

标签: node.jsasync-awaitloopbackjshtml-to-pdf

解决方案


async/await 仅适用于 Promise。所以你的库存功能需要成为一个承诺。我试图取消嵌套您的函数,希望使其更易于阅读。我没有完整的代码库,但希望能得到大致的想法。结果可能会丢失一些变量等。

// Build HTML to PDF
exports.htmlToPDF = function() {
  return new Promise(async (resolve, reject) => {
    let htmlToPDFData;

    try {
      htmlToPDFData = await htmlToPDF.build();
    } catch (err) {
      reject(err);
      return;
    }

    resolve(htmlToPDFData);
  });
};

// Read data from a file
exports.sendBackFile = function(outputPath) {
  return new Promise(async (resolve, reject) => {
    let fileData;

    try {
      fileData = await fsReadFile(outputPath, "utf8");
    } catch (err) {
      reject(err);
      return;
    }

    resolve(fileData);
  });
};

exports.PDF = function(options) {
  return new Promise(async (resolve, reject) => {
    // ...
    const htmlToPDF = new HTMLToPDF({
      // ... options
    });

    let backFileData;
    let htmlToPDFData;

    try {
      backFileData = await exports.sendBackFile(outputPath);
    } catch (err) {
      reject(err);
    }

    const contentDisposition = `attachment; filename=${filename}.pdf`;

    // Assuming this function is not a promise we just call it. Originally this was one of the callback functions.
    callWhateverFunctionWeNeedTo(
      null,
      backFileData,
      "application/pdf",
      contentDisposition,
      "SAMEORIGIN"
    );

    // start / stop Xvfb code ...
    try {
      htmlToPDFData = await exports.htmlToPDF();
    } catch (err) {
      reject(err);
    }

    // Read the file and send it back
    try {
      await exports.sendBackFile(htmlToPDFData);
    } catch (err) {
      reject(err);
    }
  });
};

// Call inventory
exports.invetory = function(html) {
  return new Promise(async (resolve, reject) => {
    try {
      await exports.PDF({ html });
    } catch (err) {
      reject(err);
    }

    resolve();
  });
};

Inventory.pdf = async (id, next) => {
  try {
    await pdf.inventory("yo");
  } catch (err) {
    console.log(err);
    return;
  }

  next();
};

推荐阅读