3

so I'm having real trouble with this - been stuck on it for weeks.

My first function queries a MySQL database and returns a response, which then gets processed in my second function.

The issue is that JS is single-threaded and I can't figure out how to get it to run in the order I want:

  1. Function 1 is fired.
  2. The function fetches the DB response and is then processed.
  3. The reponse is handed to function 2, which then does more processing.

However at the moment, the program jumps straight to function two without allowing time for the query, and the function ends up returning 'undefined'.

var test = functionOne (functionTwo);   
console.log(test);    //returning 'undefined'

function functionOne(callback) {  
            //QUERY TAKES A LONG TIME
            client.query("[QUERY]", function(err, result) {
                    callback(null, result);
            });
}

function functionTwo(err, result) {
           //More processing - slightly slow
           return result;
}

EDIT:

Here is the full file.

    var client = require('./dbHelper');
    var convert = require('./genGIF');
    var exportPPM = require('./makePPM');
    var fs = require('fs');

    module.exports = function() {
            var test = queryDatabase (handleResult);
            console.log("print: " + test);
    }

    function queryDatabase(callback) {    
            //Query our database
            client.query("SHOW TABLES FROM mathsDB", function(err, result) {
                    if (err) {
                            callback(err);
                    }

                    else {                   
                            //Calculate the length of our table and then the last image in the table
                            var currentImage = result[result.length - 1]["Tables_in_mathsDB"];
                            currentImage = currentImage.substring(5);
                            callback(null, currentImage);
                            console.log(currentImage);
                    }
            });
    }

    function handleResult(err, currentImage) {
            fs.stat("./img/image" + currentImage + ".gif", function(err, stat) {
                    if (err==null) {
                            var imageFile = "/img/image" + currentImage + ".gif";
                            return imageFile;
                    }
                    else {
                            //Check if we have a .PPM file made for the image instead, then generate a .GIF
                            fs.stat("./img/image" + currentImage + ".ppm", function(err, stat) {
                                    if (err==null) {
                                            convert.convert("image" + currentImage);
                                            var imageFile = "/img/image" + currentImage + ".gif";
                                            return imageFile;
                                    }

                                    else {
                                            //Generate the .GIF if no .GIF or .PPM already.
                                            exportPPM.make();
                                            convert.convert("image" + currentImage);
                                            var imageFile = "/img/image" + currentImage + ".gif";
                                            return imageFile;
                                    }
                            });
                    }
            });
    }
4
  • The program you posted jumps straight to the console.log, but not into functionTwo. Are you sure this is what happens? Commented Apr 20, 2016 at 12:42
  • You know that test is expected to be undefined? Commented Apr 20, 2016 at 12:45
  • @Bergi, thanks for the link, it did help to clarify the workings of asynchronicity. I understand that the test isn't assigned until after I ask it to print, and if I wanted it to print AFTER I've assigned it I could add the print into the callback function, however this same logic doesn't seem to hold for 'return'. How would I enable the program to return the correct value and not the undefined? Commented Apr 20, 2016 at 12:53
  • You cannot. The callback runs after the function has returned. The only way is to let handleResult accept another callback, and call that when it's finished - just like you did with queryDatabase. Of course you can't pass handleResult directly to queryDatabase any more, you'd need to do queryDatabase(function(err, result) { handleResult(err, result, function(test) { console.log(test); }); }); Commented Apr 20, 2016 at 13:13

3 Answers 3

2

You're returning your result as the first argument of your callback, but it's expected to be the second - in other words you're populating the err argument with your result, so the argument result will always be undefined.

So change:

function functionOne(callback) {  
            //QUERY TAKES A LONG TIME
            client.query("[QUERY]", function(err, result) {
                    callback(result);
            });
}

To this:

function functionOne(callback) {  
            //QUERY TAKES A LONG TIME
            client.query("[QUERY]", function(err, result) {
                    callback(null, result); // pass it as the second argument
            });
}

That should solve your issue.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your help. You're right, thanks for pointing that out. However this didn't fix my result. I've edited my original question to reflect a little more testing I've done.
@ChrisWalker callback functions aren't meant to return mate, that's meant for synchronous operations only - so test will almost certainly always be undefined.
Okay, thanks for the info. I think I might be structuring my program incorrectly.
@AJS offers you the solution you're looking for - in async programming, you chain callbacks rather than returning, which is an inherently synchronous operation. This can often become kind of unsightly (unless you name each callback as he has done), so I'd recommend looking into using an async library like es6-promise or async
Thanks! I had a look into using async however couldn't make it solve my issue, but then my issue was my misunderstanding of async programming ha.
|
1

this should work:

  //start execution
  functionOne (functionTwo);   


  function functionOne(callback) {  
        //QUERY TAKES A LONG TIME
        client.query("[QUERY]", function(err, result) {
                callback(null, result);
        });
  }

  function functionTwo(err, result) {
       //call function done after long processing is finished with result  
       done(err,result);
  }

  function done(err,result){
       //do your final processing here
       console.log(result);
  }

Comments

1

just change

client.query("[QUERY]", function(err, result) {
                    callback(null, result);
            });

to :

client.query("[QUERY]", function(err, result) {
                    if( err) return callback(err);
                    return callback(null, result);
            });

2 Comments

Or even simpler, function(err, result) { callback(err, result); } - or even simpler just callback
Thanks for your reply. I am using the code you've suggested - I've just cut it out of the question to help with readability. My issue isn't with processing the query - If I use a console.log, it prints the correct response. The issue is that the function isn't allowing enough time for the query to respond before returning, hence the 'undefined'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.