在节点js中正确使用asynchronous
为了克服JavaScript中的callback地狱,我试图使用从SQLServer过程中编写的遗留代码asynchronous等待。 但是我不确定我的代码是否可以正确写入。
我的第一个令人困惑的地方是,asynchronous函数返回时,是否应该返回resolve()作为布尔值,或只是返回拒绝和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
(你使它成为一个asynchronous函数),你还需要直接处理它返回的Promise。 try / catch不能处理这个asynchronous任务的结果。
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); }); };
我强烈build议阅读一些Promise相关的文章,以获得它的挂钩。 它们非常方便和强大,但是当与其他JS模式(asynchronouscallback,try / catch …)混合时也会带来一点痛苦。
- https://www.promisejs.org/
- Node.js util.promisify