我怎么能强迫这个承诺抛出特定的错误?

时间:2018-05-23 21:31:10

标签: javascript node.js promise

代码是更大更复杂的代码的一部分,所以我只是将相关的代码片段放到我的问题中。

我有这个promise.all片段:

 Promise.all(receivedObjs.arrayCMsIds.map(cmid => 
                    server.writeAttachedCMinfo(invId,cmid)))
                            .then(function (results) { // for promise all
                                return res.json(apiHelp.success(results,"success"));

                            }).catch(function (error) {
                                res.json(apiHelp.error(error, error));
                            });

这个长期复杂的writeAttachedCMinfo函数:

    server.writeAttachedCMinfo = function (invId,cmid) {
    return new Promise(function (resolve, reject) {


        console.log("writeAttachedCMinfo");
        console.log("invoiceId " + invId);
        console.log("cmid "+ cmid);

        var invoiceId = JSON.stringify(invId);
        var cmId = JSON.stringify(cmid);
        var invIdString = invoiceId;
        var cmIdString = cmId;

        invIdString = invIdString.slice(1, -1);
        cmIdString = cmIdString.slice(1, -1);

        var projection = 'gwCode certifiedInvoiceAmount buyerReference supplierReference invoiceNo invoiceSerialNo invoiceFiles creditMemos';
        ubiqInvoice.findById(invIdString, projection).then(function (dbInvoice) {

            var intInvCertifiedAmount = parseInt(dbInvoice.certifiedInvoiceAmount);


            creditMemo.findById(cmIdString).then(function (dbCreditMemo) {
                var intCreditMemoAmount = parseInt(dbCreditMemo.creditMemoAmount);

                if (intInvCertifiedAmount <= intCreditMemoAmount) {

                    console.log('cm bigger than invoice')

                    return new Error ('CMisbiggerThanInvoice');
                }

                if (dbCreditMemo.isAssociated) {

                    return new Error ('CMisAssociated');
                }

                if (dbInvoice.gwCode === "100000000000"
                    || dbInvoice.gwCode === "110000000000"
                    || dbInvoice.gwCode === "111200000000"
                    || dbInvoice.gwCode === "111100000000"
                    || dbInvoice.gwCode === "111110000000"
                ) { 

                    var creditMemoEntry = {

                        id: guid.create().value,
                        batchId: dbCreditMemo.batchId,
                        invoiceId: dbInvoice._id,
                        recordTypeCode: "CM",
                        buyerReference: dbInvoice.buyerReference,
                        supplierReference: dbInvoice.supplierReference,
                        creditMemoNo: dbCreditMemo.creditMemoNo,
                        creditMemoIssuingDate: dbCreditMemo.creditMemoIssuingDate,
                        creditMemoEffectiveDate: dbCreditMemo.creditMemoEffectiveDate,
                        lastModificationDate: dbCreditMemo.lastModificationDate,
                        currencyCode: dbCreditMemo.currencyCode,
                        creditMemoAmount: dbCreditMemo.creditMemoAmount,
                        hashCode: dbCreditMemo.hashCode,
                        description: dbCreditMemo.description,
                        uploadDate: dbCreditMemo.uploadDate,
                        isAssociated: true,
                    }


                    dbInvoice.creditMemos.push(creditMemoEntry);
                    dbInvoice.certifiedInvoiceAmount = dbInvoice.certifiedInvoiceAmount - dbCreditMemo.creditMemoAmount;
                    dbInvoice.save();


                    dbCreditMemo.isAssociated = true;

                    dbCreditMemo.save();

                    resolve(dbInvoice)


                }
                else { return new Error ('wrongggwcode'); }

    })

        });

    }), function (error) {
        console.log("error: " + error);
    }

}

我的目标是强制错误抛出以防其中一个if条件未满足,并且我想以自定义消息的形式将错误传递给客户端,以便我可以在客户端上使用它说用于显示各种错误,例如&nbsp; CMisbiggerThanInvoice&#39;

if (intInvCertifiedAmount <= intCreditMemoAmount) {

                        console.log('cm bigger than invoice')

                        return new Error ('CMisbiggerThanInvoice');
                    }

我只是试图找出一种方法将错误从writeAttachedCMinfo函数传递给promise.all的.catch(函数(错误)但是它不起作用,promise.all是即使其中一个if条件没有得到满足,也总会返回成功。

我尝试拒绝(&#39; CMisbiggerThanInvoice&#39;),拒绝(新错误(&#39; CMisbiggerThanInvoice&#39;)...都一样。

我怎样才能真正强制承诺函数返回错误

2 个答案:

答案 0 :(得分:1)

在承诺的上下文中,您应该实际抛出错误:

throw new Error('wrongggwcode');

如果这在promise构造函数回调或then回调中执行,则可以通过catch方法(或then的第二个参数)和您传递的回调的参数来捕获它它将是错误(对象)。

reject回调中调用then显然不起作用,因为您无法访问reject,但它将在promise构造函数回调中工作。

简单示例:

new Promise((resolve, reject) => {
    setTimeout( () => reject(new Error('this is an error')) );
}).then( (value) => console.log('resolved with ' + value) )
.catch( (error) => console.log('error message: ', error.message) );

嵌套

如果在then回调中嵌套了promises,请确保始终将内部promise的返回值作为外部then回调的返回值返回。

所以在你的情况下这样做:

return creditMemo.findById( ....
//^^^^

出于同样的原因,您需要这样做:

return ubiqInvoice.findById( ....
//^^^^

这会引发这个问题/答案,但最佳做法是避免嵌套承诺then一起调用。不要在嵌套的承诺上调用then,而只是在没有then调用的情况下返回承诺,并将then调用高一级,以便您拥有{平“链{ {1}}来电。这只是最佳实践的问题,尽管它应该像你已经完成的那样工作,只要你总是回报内在的承诺。

错误处理程序的位置

错误处理程序位于错误的位置;实际上你正在使用逗号运算符。简而言之,您的代码中包含以下内容:

then

逗号之后的函数永远不会执行,因为它不是方法调用的参数。它只是位于逗号运算符后面。

你想要的是对新诺言的new Promise(function (resolve, reject) { // ... // }), function (error) { console.log("error: " + error); } 方法调用,并在其中级联错误,以便catch也会收到拒绝:

Promise.all

答案 1 :(得分:1)

server.writeAttachedCMinfo()中,主要内容是:

另外,因为只有一个invId,实际上只有一个dbInvoice,并且无需在每次调用时从数据库中反复检索server.writeAttachedCMinfo()。事实上,它不应该被反复检索,否则每个dbInvoice.save()可能会覆盖同一整体事务中的早期保存。累积所有creditMemos并逐步递减单个certifiedInvoiceAmount对象中的dbInvoice会更安全,并且只需执行一个`dbInvoice.save()。

server.writeAttachedCMinfo = function(dbInvoice, cmid) {
    return creditMemo.findById(JSON.stringify(cmid).slice(1, -1))
    .then(dbCreditMemo => {
        if(parseInt(dbInvoice.certifiedInvoiceAmount) <= parseInt(dbCreditMemo.creditMemoAmount)) {
            throw new Error('CMisbiggerThanInvoice');
         // ^^^^^
        }
        /* all sorts of synchronous stuff */
        /* all sorts of synchronous stuff */
        /* all sorts of synchronous stuff */
        return dbCreditMemo; // deliver dbCreditMemo via returned Promise
    });
}

现在,在来电者中:

  • ubiqInvoice.findById()可以调用一次。
  • dbInvoice执行检查,然后失败。
  • 在每次通话时将dbInvoice而不是invId传递给server.writeAttachedCMinfo()
  • 所有保存都可以在此处完成,而不是server.writeAttachedCMinfo()

因此,调用者包含server.writeAttachedCMinfo()中的一些代码:

ubiqInvoice.findById(JSON.stringify(invId).slice(1, -1), 'gwCode certifiedInvoiceAmount buyerReference supplierReference invoiceNo invoiceSerialNo invoiceFiles creditMemos')
.then(dbInvoice => {
    if(dbCreditMemo.isAssociated) {
        throw new Error('CMisAssociated');
     // ^^^^^
    }
    if(dbInvoice.gwCode === '100000000000'
        || dbInvoice.gwCode === '110000000000'
        || dbInvoice.gwCode === '111200000000'
        || dbInvoice.gwCode === '111100000000'
        || dbInvoice.gwCode === '111110000000'
    ) {
        return Promise.all(receivedObjs.arrayCMsIds.map(cmid => {
            return server.writeAttachedCMinfo(dbInvoice, cmid)
            .catch(error => {
                console.log(error);
                return null;
            });
        }))
        .then(dbCreditMemos => {
            return Promise.all(dbCreditMemos.map(memo => {
                return memo ? memo.save() : null;
            }))
            .then(() => dbInvoice.save())
            .then(() => {
                res.json(apiHelp.success(dbInvoice, 'success'));
            });
        });
    } else {
        throw new Error('wrongggwcode');
     // ^^^^^
    }
})
.catch(error => {
    console.log('error: ' + error);
    res.json(apiHelp.error(error, error));
});

server.writeAttachedCMinfo()引起的捕捉/处理错误的整个区域需要更多思考。一方面,您可能希望保存成功的子事务并吞下错误(如上所述),而另一方面,您可能希望任何单个故障都不会导致任何保存。

另一个考虑因素是,是否应该按顺序进行server.writeAttachedCMinfo()调用,这将控制子事务访问贷方余额的优先级。就目前情况而言,对于并行请求,它有点是免费的。

这比所要求的问题要多一点,但希望它会有用。