node.js - 在 Node js 中正确使用 async wait

标签 node.js express async-await refactoring

为了克服 JavaScript 中的回调 hell ,我尝试使用 SQLServer 过程中编写的遗留代码中的异步等待。 但我不确定我的代码是否可以正确编写。

我的第一个困惑点是当异步函数返回时,它应该返回resolve()作为 bool 值,还是只返回reject并用try-catch处理?

这是我的代码片段。 请纠正我正确的方向。

apiRoutes.js

app.route('/api/dansok/cancelDansok')
    .post(dansokCancelHandler.cancelDansok);

dansokCancelController.js

const sequelize = models.Sequelize;
const jwt = require('jsonwebtoken');

async function jwtAccessAuthCheck(accessToken) {
  if (!accessToken) {
    return Promise.reject('Empty access token');
  }

  jwt.verify(accessToken,"dipa",function(err){
    if(err) {
      return Promise.reject('TokenExpiredError.');
    } else {
      return Promise.resolve();
    }
  });
}

async function checkFeeHist(dansokSeqNo) {
  let feeHist = await models.FeeHist.findOne({  
                  where: { DansokSeqNo: dansokSeqNo}
                });
  return !!feeHist;
}

async function getNextDansokHistSerialNo(dansokSeqNo) {
  ....
}

async function getDansokFee(dansokSeqNo) {
  ....
}

async function doCancel(dansokSeqNo) {
  try {
    if (await !checkFeeHist(dansokSeqNo)) {
      log.error("doCancel() invalid dansokSeqNo for cancel, ", dansokSeqNo);
      return;
    }
    let nextDansokSerialNo =  await getNextDansokHistSerialNo(dansokSeqNo);
    await insertNewDansokHist(dansokSeqNo, nextDansokSerialNo);
    await updateDansokHist(dansokSeqNo);
    await updateVBankList(dansokSeqNo, danokFee.VBankSeqNo);
    await getVBankList(dansokSeqNo);
  } catch (e) {
    log.error("doCancel() exception:", e);
  }
}

exports.cancelDansok = function (req, res) {
  res.setHeader("Content-Type", "application/json; charset=utf-8");
  const dansokSeqNo = req.body.DANSOKSEQNO;
  const discKindCode = req.body.HISTKIND;
  const worker = req.body.PROCWORKER;
  const workerIp = req.body.CREATEIP;
  const accessToken = req.headers.accesstoken;

  //check input parameter
  if (!dansokSeqNo || !discKindCode || !worker || !workerIp) {
    let e = {status:400, message:'params are empty.'};
    return res.status(e.status).json(e);
  } 

  try {
    jwtAccessAuthCheck(accessToken)
    .then(() => {
      log.info("jwt success");
      doCancel(dansokSeqNo).then(() => {
        log.info("cancelDansok() finish");
        res.status(200).json({ message: 'cancelDansok success.' });
      });
    });
  } catch(e) {
    return res.status(e.status).json(e);
  }
};

最佳答案

您需要重写jwtAccessAuthCheck(accessToken),以便它跟踪其嵌套任务的结果。在您编写的代码中:

// Code that needs fixes!
async function jwtAccessAuthCheck(accessToken) {

  // This part is fine. We are in the main async flow.
  if (!accessToken) {
    return Promise.reject('Empty access token');
  }

  // This needs to be rewritten, as the async function itself doesn't know anything about
  // the outcome of `jwt.verify`... 
  jwt.verify(accessToken,"dipa",function(err){
    if(err) {
      // This is wrapped in a `function(err)` callback, so the return value is irrelevant
      // to the async function itself
      return Promise.reject('TokenExpiredError.');
    } else {
      // Same problem here.
      return Promise.resolve();
    }
  });

  // Since the main async scope didn't handle anything related to `jwt.verify`, the content
  // below will print even before `jwt.verify()` completes! And the async call will be
  // considered complete right away.
  console.log('Completed before jwt.verify() outcome');

}

更好的重写是:

// Fixed code. The outcome of `jwt.verify` is explicitly delegated back to a new Promise's
// `resolve` and `reject` handlers, Promise which we await for.
async function jwtAccessAuthCheck(accessToken) {
  await new Promise((resolve, reject) => {

    if (!accessToken) {
      reject('Empty access token');
      return;
    }

    jwt.verify(accessToken,"dipa",function(err){
      if(err) {
        reject('TokenExpiredError.');
      } else {
        resolve();
      }
    });

  });

  // We won't consider this async call done until the Promise above completes.
  console.log('Completed');

}

也适用于此特定用例的替代签名:

// Also works this way without the `async` type:
function jwtAccessAuthCheck(accessToken) {
  return new Promise((resolve, reject) => {
    ...
  });
}
<小时/>

关于您的 cancelDansok(req, res) 中间件,由于 jwtAccessAuthCheck 保证返回 Promise (您将其设为异步函数),因此您还需要直接处理其返回的 Promise。没有 try/catch 可以处理此异步任务的结果。

exports.cancelDansok = function (req, res) {

  ...

  jwtAccessAuthCheck(accessToken)
    .then(() => {
      log.info("jwt success");
      return doCancel(dansokSeqNo);
    })
    .then(() => {
      log.info("cancelDansok() finish");
      res.status(200).json({ message: 'cancelDansok success.' });
    })
    .catch(e => {
      res.status(e.status).json(e);
    });

};
<小时/>

我强烈建议阅读一些与 Promise 相关的文章来掌握它的窍门。它们非常方便且功能强大,但与其他 JS 模式(异步回调、try/catch...)混合时也会带来一些麻烦。

关于node.js - 在 Node js 中正确使用 async wait,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47630266/

相关文章:

c# - 如何在C#中成功下载一个.exe文件?

node.js - 将域重定向到 ip 和端口

node.js - 使用 CircleCI 部署到 Firebase 托管

node.js - https请求中承载 token 的用法

javascript - 从返回 "UNSPECIFIED_ERROR"的模板创建信封

mysql - MySQL 查询中的变量导致错误

用于构建 API 的类似 Express 的框架

node.js - 使用 Node.js 将文件从字符串上传到 Box API

dictionary - 如何避免通过foreach函数在dart Map中使用await键

javascript - 导出异步等待变量并在 JS 中完成 "awaiting"后将其导入另一个文件