Masood
Masood

Reputation: 1594

Nesting .then() and catch in Javascript promise

I'm not experienced with Javascript promises and recently I started using promises instead of callbacks in my Javascript projects.
When I tried to run several promise functions one after another I landed in a nested chaos of then(). The code works exactly as expected, but my question is that if this is the way to resolve several promise functions one after another then what is the advantage of using promises instead of callbacks.
If I'm not doing it the right way, then it is a request from you guys to show me the proper way of resolving nested promises. Below is my code that I don't like it they way it looks:

exports.editExpense = (req, res, next) => {
    Account.findAll().then(accounts => {
        Budget.findAll().then(budgets => {
            Expense.findAll().then(expenses => {
                Expense.findByPk(id).then(expense => {
                    res.render('expenses/index', {
                        urlQuery: urlQuery,
                        expenses: expenses,
                        expense: expense,
                        accounts: accounts,
                        budgets: budgets
                    });
                })
            })
        })
    }).catch(error => console.log(error));
};

Upvotes: 3

Views: 3455

Answers (2)

vleonc
vleonc

Reputation: 227

If you prefer to use the then catch structure, in order to take fully advantage of it I recommend you not to nest them. Of course you can, but then you should put a .catch() after each of them. That's why the async introduction made an easier code to read and handle errors, as it simplifies it with the try catch structure.

If you pipe multiple .then(), you can return a value as a promise from each of them that can be used inside the next one once the promise resolves. The only thing is that you loose these values unless you save them either in req with new properties or in variables declared outside the pipe of .then().

That's why, in this snippet, I declared all the variables at the beginning in order to save all the values and use them in the final res

exports.editExpense = (req, res, next) => {
    
    let accounts;
    let budgets;
    let expenses;

    Account.findAll()
        .then(fetchedAccounts => {
            accounts = fetchedAccounts;
            return Budget.findAll()
        })
        .then(fetchedBudgets => {
            budgets = fetchedBudgets;
            return Expense.findAll()
        })
        .then(fetchedExpenses => {
            expenses = fetchedExpenses
            return Expense.findByPk(id)
        })
        .then(expense => {
            return res.render('expenses/index', {
                urlQuery: urlQuery,
                expenses: expenses,
                expense: expense,
                accounts: accounts,
                budgets: budgets
            });
        })
        .catch(error => console.log(error));
};

Upvotes: 6

Shivam
Shivam

Reputation: 3642

You can use async/await structure for better formatting

exports.editExpense = async(req, res, next) => {
    try {
      let accounts = await Account.findAll();
      let budgets = await Budget.findAll();
      let expenses = await Expense.findAll()
      let expense = await Expense.findByPk(id);
      if (expense) {
        res.render('expenses/index', {
          urlQuery: urlQuery,
          expenses: expenses,
          expense: expense,
          accounts: accounts,
          budgets: budgets
        });
      } else {
        console.log('else') //<<- Render/Handle else condition otherwise server will hang.
      }
    } catch (error) {
      console.error(error)
    }

You should try to minimize the amount of async calls you make in a function as it will impact your performance.

Upvotes: 3

Related Questions