[英]Node.js - Promise execution order issue
我對異步操作的執行順序有疑問。 下面是我的代碼,它向第3方API發送請求以創建發票項目,然后向創建發票的另一個請求發送。 我的問題是,在創建調整發票項目之前先創建了發票。
function createInvoiceItems(invoice, customerDetails) {
return new Promise((resolve, reject) => {
const invoiceItems = invoice.invoiceItems;
const invoiceCurrency = invoice.currency;
const promises = invoiceItems.map((invoiceItem) =>
new Promise((fulfill, deny) => {
invoiceItem.currency = invoiceCurrency;
createInvoiceItem(customerDetails, invoiceItem)
.then((item) => fulfill(invoiceItem.amount))
.catch((error) => deny(error));
})
);
return Promise.all(promises)
.then((lineTotals) => {
if (lineTotals.length > 0) {
const invoiceTotal = calculateInvoiceTotal(lineTotals);
console.log('INVOICE TOTALS ######################', invoiceTotal);
const customerCommitment = invoice.commitment;
//Create adjustment invoice item
if (invoiceTotal < customerCommitment) {
const adjustmentAmount = (customerCommitment - invoiceTotal);
console.log('ADJUSTMENT AMOUNT ######################', adjustmentAmount);
const invoiceItem = {
currency: invoiceCurrency,
amount: adjustmentAmount,
description: 'Adjustment',
};
createInvoiceItem(customerDetails, invoiceItem)
.then((item) => {
if (typeof item === 'object') {
return resolve(customerDetails.stripeId);
}
})
.catch((error) => reject(error));
}
}
})
.then(() => resolve(customerDetails.stripeId))
.catch((error) => reject(error));
});
}
/**
* Generates customer invoices
* @param invoices
*/
function generateInvoices(invoices) {
return new Promise((resolveInvoice, rejectInvoice) => {
const promises = invoices.map((invoice) =>
new Promise((resolve, reject) => {
let invoiceDetails;
getInvoice(invoice)
.then((invoiceObject) => {
invoiceDetails = invoiceObject;
return getCustomerDetails(invoiceDetails.customerId);
})
.then((customerDetails) => createInvoiceItems(invoiceDetails, customerDetails))
.then((customerId) => createInvoice(customerId))
.then((thirdPartyInvoice) => {
invoiceDetails.close = true;
updateInvoiceFile(invoiceDetails)
.then(() => resolve(thirdPartyInvoice.id));
})
.catch((error) => reject(error));
})
);
Promise.all(promises)
.then((invoice) => {
if (invoice.length > 0) {
return resolveInvoice(invoice);
}
return rejectInvoice('Invoice could not be generated');
})
.catch((error) => rejectInvoice(error));
});
}
此代碼有什么問題?
發生這種情況是由於以下構造:
.then(… => {
…
createInvoiceItem(customerDetails, invoiceItem)
.then(… => {
resolve(customerDetails.stripeId);
})
})
.then(() => resolve(…))
由於您沒有從第一個回調中return
任何內容,因此Promise鏈不會等待任何內容,並且調用會在第二個回調中立即resolve
。 createInvoiceItem
之后調用的resolve
來不及了。
但是,真正的問題是Promise
構造函數antipattern的普遍使用。 您不得在任何地方使用Promise
構造函數- then
鏈子! 這大大簡化了您的代碼:
function createInvoiceItems(invoice, customerDetails) {
const invoiceItems = invoice.invoiceItems;
const invoiceCurrency = invoice.currency;
const promises = invoiceItems.map(invoiceItem => {
invoiceItem.currency = invoiceCurrency;
return createInvoiceItem(customerDetails, invoiceItem)
.then(item => invoiceItem.amount);
});
return Promise.all(promises)
.then(lineTotals => {
if (lineTotals.length > 0) {
const invoiceTotal = calculateInvoiceTotal(lineTotals);
console.log('INVOICE TOTALS ######################', invoiceTotal);
const customerCommitment = invoice.commitment;
//Create adjustment invoice item
if (invoiceTotal < customerCommitment) {
const adjustmentAmount = (customerCommitment - invoiceTotal);
console.log('ADJUSTMENT AMOUNT ######################', adjustmentAmount);
const invoiceItem = {
currency: invoiceCurrency,
amount: adjustmentAmount,
description: 'Adjustment',
};
return createInvoiceItem(customerDetails, invoiceItem)
.then(item => {
if (typeof item === 'object') {
return customerDetails.stripeId;
}
// not sure what should happen otherwise?
});
}
} // else
return customerDetails.stripeId;
});
}
function generateInvoices(invoices) {
const promises = invoices.map(invoice =>
getInvoice(invoice)
.then(invoiceObject =>
getCustomerDetails(invoiceDetails.customerId);
.then(customerDetails => createInvoiceItems(invoiceDetails, customerDetails))
.then(customerId => createInvoice(customerId))
.then(thirdPartyInvoice => {
invoiceObject.close = true;
return updateInvoiceFile(invoiceDetails)
.then(() => thirdPartyInvoice.id);
})
)
);
return Promise.all(promises)
.then(invoice => {
if (invoice.length > 0)
return invoice;
else
throw new Error('Invoice could not be generated');
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.