簡體   English   中英

Node.js-承諾執行順序問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM