Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional .then execution

How to conditionally skip a promise and do nothing. I have created a nested promise, by which i have 7 .then's. But conditionally, i need to skip few .then and do nothing in that block, how to achive this ?

My FULL CODE:

const admin = require('firebase-admin');
const rp = require('request-promise');

module.exports = function(req, res) {

const phone = String(req.body.phone).replace(/[^\d]/g, '');
const amount = parseInt(req.body.amount);
const couponCodeName = (req.body.couponCodeName);
const couponUsage = parseInt(req.body.couponUsage);
const usersCouponUsage = parseInt(req.body.usersCouponUsage);
const finalAddress = (req.body.finalAddress);
const planName = (req.body.planName);
const saveThisAddress = (req.body.saveThisAddress);
const orderNumber = (req.body.orderNumber);
const pay_id = (req.body.pay_id);

const options = {
    method: 'POST',
    uri:`https://..........`,
    body: {
        amount
    },
    json: true
};

return admin.auth().getUser(phone)
.then(userRecord => {

    return rp(options)
})
.then((orderResponse) => {
    return admin.database().ref('trs/'+ phone)
        .push({ pay_id: orderResponse.id })
    })
.then(() => {
    return admin.database().ref('ors/'+ phone)
        .push({ pay_id })
})
.then(() => { 
    return saveThisAddress === true ? 
        admin.database().ref('address/'+phone)
            .push({address: finalAddress}) : null
})
.then(() => {
    return admin.database().ref('deliveryStatus/'+phone+'/'+orderNumber)
        .set({ plan: planName === "" ? "Single Day Plan" : planName, delivered: false}, () => {
            res.status(200).send({ success:true })
        })
}) 
.then(() => {
    return couponCodeName === "" ? null : 
        admin.database().ref(`couponCodes/${couponCodeName}`)
            .update({couponUsage: couponUsage + 1 })
})
.then(() => {
    return usersCouponUsage === "" ? null : 
        admin.database().ref(`couponUsage/${phone}`)
            .update({ [couponCodeName]: usersCouponUsage + 1 })
})
.catch((err) => {
    res.status(422).send({ error: err })
})    
 .catch((err) => {
 res.status(422).send({error: err });
 });
 }

From the above code, last two .then has a condition return couponCodeName === "" ? null : code... )}.

What i need to achieve is, when the couponCodeName === "" then, it should skip the .then block and do nothing. But, i am returning null in this, it throws an unhandled rejection error. So how to achieve this ? How to skip a .then, and do nothing ( Its important to do nothing, simply skip it ) How to do this ?

THE ERROR I AM GETTING IS: The error i am getting from these nested .then is "Unhandled rejection" & "Error: Can't set headers after they are sent."

Error From Google Cloud Function

Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:369:11)
at ServerResponse.header (/var/tmp/worker/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/var/tmp/worker/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/var/tmp/worker/node_modules/express/lib/response.js:267:15)
at ServerResponse.send (/var/tmp/worker/node_modules/express/lib/response.js:158:21)
at admin.auth.getUser.then.then.then.then.then.then.then.catch.catch (/user_code/request_payment_details.js:86:28)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)

And also

Unhandled rejection

Note: Node Js version : 6 ( So i think officially , i cant use async and await )

like image 963
Dazzile Pro Avatar asked Mar 17 '19 06:03

Dazzile Pro


People also ask

What is meant by conditional execution?

Conditional execution controls whether or not the core will execute an instruction. Most instructions have a condition attribute that determines if the core will execute it based on the setting of the condition flags.

What is conditional execution in Python?

In order to write useful programs, we almost always need the ability to check conditions and change the behavior of the program accordingly. Conditional statements give us this ability. The simplest form is the if statement: if x > 0 : print('x is positive')

How do you run a conditional statement?

if statements are used to conditionally execute statement lists according to the value of a boolean expression. In this form, the if keyword is followed by a boolean expression, the keyword then, a list of statements and the final keyword end.

How many number of statements do you need in the conditionals Is there a limit?

There is no limit on the number of statements that can appear under the two clauses of an if else statement, but there has to be at least one statement in each block. Occasionally, it is useful to have a section with no statements (usually as a place keeper, or scaffolding, for code you haven't written yet).


2 Answers

Maybe you can use async/await for this, as synchronization is what you need:

async function doSomething() {
    var res1 = await promise1();
    if (res1 === xxx) {
        var res2 = await promise2();
    } else {
        ...
    }
}
like image 82
ttulka Avatar answered Sep 19 '22 23:09

ttulka


Part 1: Your error handler should not crash.

If you call res.status(200), Express starts streaming data to the client (the headers are already sent). You can't change the response status afterwards with res.status(500), as the status code is already on its way to the client.

 stuff()
 .then(result => {
   res.status(200).send(result); // server starts sending
 }).then(moreStuff) // error occurs here
 .catch(error => {
   res.status(500).send(error); // fails, as server is already sending
 });

To resolve this, you should only start streaming any data when all of your tasks are done:

 stuff().then(moreStuff).then(evenMoreStuff) // error occurs here
   .then(result => {
      res.status(200).send(result); // doesnt get executed
   }).catch(error => {
      console.error(error);
      res.status(500).send("Whoops, server error\n" + error.message); // works
   });

Part 2: The logic inside your error should not throw at all.

Now that the error handler works correctly you should be able to find out what's actually going wrong in your code.

(We can't help you with that without a proper error message)


Part 3: Implement the wanted conditional execution:

To conditionally execute promises, you have to nest them:

 a().then(() => {
  if(!stuff) return; // exit early, continue at next then

  return b().then(c); // conditionally execute b and c
 }).then(rest); // executes after b and c if stuff is true

Part 4: Now that everything is working, you could refactor your code to async / await to make it way more readable:

As you pointed out, v6 dpes not support async / await, you'd have to you migrate to v8 or you transpile it down with webpack:

module.exports = async function(req, res) {
  try {
     //...
     const userRecord = await admin.auth().getUser(phone);
     const orderResponse = await rp(options)

     await admin.database().ref('trs/'+ phone)
      .push({ pay_id: orderResponse.id });

     await admin.database().ref('ors/'+ phone)
      .push({ pay_id })

     if(saveThisAddress === true) {
       await admin.database().ref('address/'+phone)
        .push({address: finalAddress});
     }

     await admin.database().ref('deliveryStatus/'+phone+'/'+orderNumber)
      .set({ plan: planName === "" ? "Single Day Plan" : planName, delivered: false});

     if(couponCodeName !== "") {       
       await admin.database().ref(`couponCodes/${couponCodeName}`)
        .update({couponUsage: couponUsage + 1 });
     }

     if(usersCouponUsage !== "") {
       await admin.database().ref(`couponUsage/${phone}`)
        .update({ [couponCodeName]: usersCouponUsage + 1 });
     }

     res.status(200).send({ success:true });
  } catch(error) {
    console.error("Error inside API", error);
    res.status(422).send({ error });
  }
};
like image 26
Jonas Wilms Avatar answered Sep 20 '22 23:09

Jonas Wilms