2017-12-04 10 views
1

JavaScriptでコールバックhellを克服するために、SQLServerプロシージャで記述されたレガシーコードから非同期待機を使用しようとしています。 しかし、私のコードが正しく書かれているかどうかはわかりません。asyncをノードjsで適切に使用する

私の最初の混乱する点は、async関数が返されたとき、resolve()をブール値として返すか、拒否を返してtry-catchで処理するかどうかです。

ここに私のコードスニペットがあります。 正しい方向に修正してください。それはそのネストされたタスクの結果を追跡するようにあなたがjwtAccessAuthCheck(accessToken)を書き換える必要があります

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

答えて

1

。あなたが書いたコードでは:

// 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も直接処理する必要があります。 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); 
    }); 

}; 

私は強く、それのこつを得るためにいくつかの約束に関連した記事を読んでお勧めします。彼らは非常に便利で強力ですが、他のJSパターン(非同期コールバック、try/catch ...)と混在しても少し苦労します。

関連する問題