【问题标题】:Using async await properly in node js在节点 js 中正确使用异步等待
【发布时间】:2018-05-17 17:39:24
【问题描述】:

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

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

这是我的代码 sn-ps。 请纠正我正确的方向。

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);
  }
};

【问题讨论】:

    标签: node.js express async-await refactoring


    【解决方案1】:

    您需要重写 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...)混合时也会带来一点痛苦。

    【讨论】:

      猜你喜欢
      • 2017-01-24
      • 1970-01-01
      • 2020-12-02
      • 1970-01-01
      • 2018-12-30
      • 1970-01-01
      • 2020-09-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多