0

Background

My issue is understanding a scope and how to use callback functions appropriately. I can not seem to string the events along in order as I try to plan. I have had trouble reading posts and relating them to my current problems. I guess what I really do not get is how to implement the logic.

Question

I have a few scenarios that are causing me problems in my application. They all revolve around a situation where I need data which is not in scope yet. But the function already has a callback function.

Example

This function inserts data into a database.

   updateProfile: function (req, res) {
    pool.getConnection(function (err, connection) {
        var email = req.body.email;
        var sql = 'INSERT INTO rw_users SET email = ?';
        var params = [email];

        connection.query(sql, params, function (err, results, fields) {
            if (err) {
                res.status(500).send();
                throw err;
            }
            connection.release();
        });
    });
},

This next function needs the ID from the user which was just created.

 createCustomerProfile: function (email, id) {
            merchant.createCustomerProfile(email, id, function callback(merchantRes){
                    pool.getConnection(function (err, connection) {
                var sql = 'UPDATE rw_user SET auth_customer_id = ? WHERE email = ?';
                var params = [merchantRes, email];
                connection.query(sql, params, function (err, results, fields) {
                    if (err) {
                        throw err;
                    }
                    console.log('new customer created at authorize.net');
                });
            });
          });
        }, 

In the function updateProfile() I am creating a new user in my database. In the second function createCustomerProfile() I need the ID of the newly created user that was entered in function one.

Please show me a way to handle functions like this. Where I need the data from the first process so I can use it in the second function. This gets worst as it goes on because when function two is complete it will have a new customerID in its response from the API call it makes. That response also needs to make another database query to update the row with its ID. Then once these 2 functions are done I need to query the database again to return the whole row.

To break this down,

  1. Create the user in the database.
  2. Using the id and email of the new user created in function 1. A new customer account id with authorize.net api gets created in function 2.
  3. Insert the new customer id from the response of the authorize.net API into the new user row that was created in function one.
  4. Return the whole row.

My question to be clear. What is a possible solution to use to be able to take tasks like in my list and clearly implement them to be dealt with in order so I can use the response from each one when it exists in scope?

Piotr Dawidiuk
  • 2,961
  • 1
  • 24
  • 33
wuno
  • 9,547
  • 19
  • 96
  • 180
  • if they are two different function then use callback as the 3rd params to execute the createCustomerProfile – Vinod Louis Feb 07 '17 at 08:46
  • 1
    I'm afraid your question isn't clear. Is your question about JavaScript (how to string the functions together when they produce results asynchronously), or is it about MySQL and returning information after an insert? Also: Please keep extraneous detail out of the question. Your entire first paragraph and about half the rest of the text is extraneous and only gets in the way of people reading it and providing answers for you. – T.J. Crowder Feb 07 '17 at 08:46
  • The MySQL question (if that's what this is) is answered here: http://stackoverflow.com/questions/31371079/retrieve-last-inserted-id-with-mysql A trivial search for "nodejs mysql get last id" turned it up. More on searching [here](/help/searching). – T.J. Crowder Feb 07 '17 at 08:47
  • I am sorry about that. Yes my question is how to confidently string the order of events out. The list I made at the end was me trying to make it more clear. I terribly want to understand this so I do not keep coming back to these issues. Would you like me to edit the question? Or do you get what I mean now? – wuno Feb 07 '17 at 08:47
  • For the stringing together, look into "promises" (and soon the new `async`/`await` syntax, but for now, promises). – T.J. Crowder Feb 07 '17 at 08:52
  • @Vindod Louis what do you mean use call back as 3rd param? In which function? You mean add a 3rd paramater to updateProfile that calls function 2? – wuno Feb 07 '17 at 08:52
  • Hey guys I really appreciate the comments, but is there anyway one of you can please put together an answer for me. I really would appreciate a straight forward answer / example so I can understand. I just cant figure out how to make this work everytime I get in this situation. If someone can see what I am missing here would you please explain it to me? – wuno Feb 07 '17 at 09:54
  • You seem to already know that [you need a callback](http://stackoverflow.com/q/14220321/1048572), however neither `updateProfile` nor `createCustomerProfile` have a callback parameter? – Bergi Feb 07 '17 at 09:56
  • Yes. I am not understand how to implement a callback function which will take data from the inner most function response. – wuno Feb 07 '17 at 09:58
  • Please let me know if my question is not clear. I will edit it: but I think i have made it clear that I don't know the solution to my problem. – wuno Feb 07 '17 at 09:59

1 Answers1

1

The easiest way to implement your program is to use nested callbacks but this easily becomes messy and hard to maintain your codes. We can use promises or generators for doing this in more elegant way. First of all, let's have a look at the following codes (simple one).

     const test1= () => {
         return new Promise((resolve,reject)=>{
              setTimeout(function(){ <-- async operation
                 resolve(10);
             })
         })
     }

     const test2= (data) => {
         return new Promise((resolve,reject)=>{
                    setTimeout(function(){ <-- async operation
                         resolve(data+20)
                    })
                })
     }

     test1()
     .then(test2)
     .then((finalData)=>{console.log(finalData)});

This will give us value 30. So how does this work. Both test1 and test2 return promise object which has a method name 'then'.

   new Proimse((resolve,reject)=>{ async operation comes here , when the operation 
done successfully , we resolve it, otherwise reject , })

The then method expecting a function and we can pass the parameter through resolve function. But only one parameter is expected, so if more than one parameter are needed, objects or arrays are needed. If you can understand the codes above, let's refactor you codes a bit

     getConnection:function(req,res){
           return new Promise((resolve,reject)=>{
                 pool.getConnection(function (err, connection) {
                        if(err) return reject(err);
                        resolve({connection,req,res});
             });
             })
     },

     updateProfile:function(obj){
         const { connection,req,res } = obj;
         return new Promise((resolve,reject)=>{
             var email = req.body.email;
             var sql = 'INSERT INTO rw_users SET email = ?';
             var params = [email];
             connection.query(sql, params, function (err, results, fields) {
                     if (err) return reject(err);
                     resolve({email,results,connection});
             });
         })
     },

     createCustomerProfile: function (obj) {
                   const { email,results,connection } = obj;
                     return new Promise((resolve,reject)=>{
                         merchant.createCustomerProfile(email, results.id, function callback(merchantRes){
                                 var sql = 'UPDATE rw_user SET auth_customer_id = ? WHERE email = ?';
                                 var params = [merchantRes, email];
                                 connection.query(sql, params, function (err, results, fields) {
                                         if (err) {
                                                 throw err;
                                         }
                                         console.log('new customer created at authorize.net');
                                         connection.release();
                                 });
                     });
                     })
  }

    yourModule.getConnection(req,res)
              .then(yourModule.updateProfile)
              .then(yourModule.createCustomerProfile)
              .catch((err)=>{console.log(err)})

Now you need to modify this code so that is works with your module.

Mia
  • 184
  • 5