0

When I have two methods shoppingCartPlaceOrder() and shoppingCartSetOrderLineItem(). I need wait when shoppingCartPlaceOrder() ends and get Id of order from this method. Then it's needed to execute shoppingCartSetOrderLineItem() and use that Id. There is an catch in handlePlaceOrder(): 'this.shoppingCartPlaceOrder(): error'.

Here is simplified code:

import { LightningElement } from 'lwc';

export default class ShoppingCart extends LightningElement {
  nameOfOrderFromCart;
  sumOfPricesFromCart = 0;
  orderId;
  lineItemsIds;

  shoppingCartPlaceOrder() {
    return new Promise(function(resolve, reject) {
      placeOrder({
        nameOfOrder : this.nameOfOrderFromCart, 
        price : this.sumOfPricesFromCart
      })
      .then( result => {
        resolve('resolve: It\'s written. Order Id: ' + result);
        this.orderId = result; // add Id of order in database
      })
      .catch(error => {
        reject('reject: Error writing order.');
        debugger;
      });
    });
  }

  shoppingCartSetOrderLineItem() {
    setOrderLineItem({
      orderId : this.orderId, // Id from shoppingCartPlaceOrder() -> placeOrder()
      line : 1;
    })
    .then( result => {
      this.lineItemsIds = result; // add actual Id of order line item in database
    })
    .catch(error => {
      debugger;
    });
  }

  handlePlaceOrder() {
    // waiting for Order Id
    this.shoppingCartPlaceOrder()
    .then(function(result) {
      console.log('this.shoppingCartPlaceOrder(): success'); // => I would like executed this line
    })
    .catch(function(error) {
      console.log('this.shoppingCartPlaceOrder(): error'); // => this line is executed, why?
    })

    this.shoppingCartSetOrderLineItem();
  }

Does new Promise is wrong in method shoppingCartPlaceOrder()? How to do it, that first will be executed this.shoppingCartPlaceOrder() and when it ends, then will be executed this.shoppingCartSetOrderLineItem()?

Elo
  • 226
  • 5
  • 19
  • [What is the explicit promise construction antipattern and how do I avoid it?](https://stackoverflow.com/q/23803743) – VLAZ Apr 09 '21 at 08:20

3 Answers3

1

The only thing you need to do basically is just chain your this.shoppingCartSetOrderLineItem() with the previous promise result as you can see in the snippet I have pasted.

handlePlaceOrder() {
    // waiting for Order Id
    this.shoppingCartPlaceOrder()
        .then(function(result) {
            console.log('this.shoppingCartPlaceOrder(): success'); // => I would like executed this line
    })
    .catch(function(error) {
        console.log('this.shoppingCartPlaceOrder(): error'); // => this line is executed, why?
    }).then(function(res) {
        this.shoppingCartSetOrderLineItem();
    }
 }

But much better would be to use async-await, it's cleaner and more readable, I would say.

const dummyPromise = new Promise((resolve, reject) => {
  reject("dummyPromise rejected");
});

const shoppingCartPlaceOrder = async () => {
  return new Promise((resolve, reject) => {
    console.log("shoppingCartPlaceOrder executed");

    dummyPromise.then(res => {
      resolve('placeOrder resolved');
    }).catch(err => {
      reject('placeOrder rejected');
      debugger;
    });
  });
}

const shoppingCartSetOrderLineItem = () => {
  console.log("shoppingCartSetOrderLineItem executed");
}

const handlePlaceOrder = () => {
  shoppingCartPlaceOrder().then(res => {
     console.log(res);
  }).catch(err => {
     console.log(err);
  }).then(res => {
    shoppingCartSetOrderLineItem();
  });
};

const handlePlaceOrderAsync = async () => {
  console.log('async execution');

  try {
    const value = await shoppingCartPlaceOrder();
    console.log(value);
  } catch(e) {
    console.log(e);
  }

  shoppingCartSetOrderLineItem();
}

// handlePlaceOrder();
handlePlaceOrderAsync();
pesoklp13
  • 339
  • 2
  • 11
  • Why an `async` function with no `await` in it? Why return a Promise that resolves inside a `.then()`, instead of returning `placeOrder` directly, which is itself a Promise? Why mix `.then()` and `await`? This code looks so unnecessarily complicated, it's Promises with extra steps. – Jeremy Thille Apr 09 '21 at 08:26
1

The old .then() style is always a guaranteed headache. The newer async/await is so much easier to write, read and deal with :

import { LightningElement } from 'lwc';

export default class ShoppingCart extends LightningElement {
    nameOfOrderFromCart;
    sumOfPricesFromCart = 0;
    orderId;
    lineItemsIds;

    async shoppingCartPlaceOrder() {
        let result;

        try {
            result = await placeOrder({
                nameOfOrder: this.nameOfOrderFromCart,
                price: this.sumOfPricesFromCart
            });
        } catch (error) {
            debugger;
            return error;
        }
        return result;
    }

    async shoppingCartSetOrderLineItem() {
        try {
            this.lineItemsIds = await setOrderLineItem({
                orderId: this.orderId, // Id from shoppingCartPlaceOrder() -> placeOrder()
                line: 1
            })
        } catch (error) {
            debugger;
        }
    }

    async handlePlaceOrder() {
        const orderId = await this.shoppingCartPlaceOrder();
        console.log(`Writen. OrderID = ${orderId}`);
        await this.shoppingCartSetOrderLineItem();
    }
}
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • Nice code, thank you. It works. Small fix: after `line: 1` is without `;`. And in handlePlaceOrder() should be set order id to the global variable `this.orderId`, otherwise it would not work. – Elo Apr 09 '21 at 14:32
  • What do you mean `after line: 1 is without ;` ? – Jeremy Thille Apr 09 '21 at 14:51
  • I mean, that ";" doesn't belong in method shoppingCartSetOrderLineItem() at code `this.lineItemsIds = await setOrderLineItem({ orderId: this.orderId, line: 1 })`. – Elo Apr 10 '21 at 07:54
0

The resulting code I used:

import { LightningElement } from 'lwc';

export default class ShoppingCart extends LightningElement {
    nameOfOrderFromCart;
    sumOfPricesFromCart = 0;
    orderId;
    lineItemsIds;

    async shoppingCartPlaceOrder() {
        let result;

        try {
            result = await placeOrder({
                nameOfOrder: this.nameOfOrderFromCart,
                price: this.sumOfPricesFromCart
            });
        } catch (error) {
            debugger;
            return error;
        }
        return result;
    }

    async shoppingCartSetOrderLineItem() {
        try {
            this.lineItemsIds = await setOrderLineItem({
                orderId: this.orderId, // Id from shoppingCartPlaceOrder() -> placeOrder()
                line: 1
            })
        } catch (error) {
            debugger;
        }
    }

    async handlePlaceOrder() {
        this.orderId = await this.shoppingCartPlaceOrder();
        console.log(`Written. OrderID = ${this.orderId}`);
        await this.shoppingCartSetOrderLineItem();
        console.log(`Written. lineItemsIds = ${this.lineItemsIds}`);
    }
}
Elo
  • 226
  • 5
  • 19