代码是更大更复杂的代码的一部分,所以我只是将相关的代码片段放到我的问题中。
我有这个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;)...都一样。
我怎样才能真正强制承诺函数返回错误?
答案 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()
中,主要内容是:
new Promise()
包装 - 没有必要 - (Promise constructor anti-pattern)。另外,因为只有一个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()
调用,这将控制子事务访问贷方余额的优先级。就目前情况而言,对于并行请求,它有点是免费的。
这比所要求的问题要多一点,但希望它会有用。