grit96
grit96

Reputation: 62

Node.js extract value from callback function

I have a server file with a switch using the URL to display appropriate content. One of the cases is /users which should display a JSON string of a certain table. This is returned from a mysql file.

server.js

var http = require('http')
var url = require('url')
var port = 8080

function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname
    console.log('Request for ' + pathname + ' received.')

    response.writeHead(200, {'Content-Type': 'text/html'})
    response.write(run(pathname))
    response.end()
}

function run(pathname) {
    switch(pathname) {
        case '/':
            response = 'Welcome to my little test'
            break
        case '/time':
            response = 'The time is ' + new Date().toLocaleTimeString()
            break
        case '/users':
            var response
            require('./mysql').getUsers(function(users) {
                console.log(users)
                response = users
            })
            return response
            break
        default:
            response = 'Unable to locate the requested page'
    }
    return response
}

http.createServer(onRequest).listen(port)
console.log('Server started on port ' + port + '.')

mysql.js

var mysql = require('mysql')

var connection = mysql.createConnection({ 
    user: "root", 
    password: "password", 
    database: "main"
})

exports.getUsers = function(callback) {
    connection.query('SELECT * FROM users;', function (error, rows, fields) {
        callback(JSON.stringify(rows));
    });
};

The console.log(users) in server.js displays the JSON string fine, but I cannot figure out how to get the value out of the callback and into the response variable.

Any ideas will be greatly appreciated.

Upvotes: 1

Views: 4738

Answers (3)

Nitin...
Nitin...

Reputation: 1314

You do not need to serialize the mysql returned rows to use it. Either you can process it within getUsers, or return it back to the controller. If you return it, change code to:

exports.getUsers = function(callback) {
    connection.query('SELECT * FROM users;', function (error, rows, fields) {
        callback(rows);
    });
};

Now within the server.js file, you can process the returned rows, like:

case '/users':
  var response = ''
  require('./mysql').getUsers(function(users) {
    for (var i in users) {
      var user = users[i];
      var userId = user.id;
      var userName = user.user_name;
      response += "User - ID: "+userId+" Name: "+userName+"\n";
    }
  })
  return response;
break;

You can process

Upvotes: 0

allen wang
allen wang

Reputation: 1147

you can't do it like this. the problem is easy. let's talk about it: function getUsers is an asynchronous. so the code follow runs like this:

 case '/users':
   var response
   require('./mysql').getUsers(function(users) {
     console.log(users)
     response = users
   })
   return response
   break

first, run require('./mysql').getUser() , then it will do return response directly, then break . when the getUser function is finished, it will run

 function(users) {
     console.log(users)
     response = users
   })

so, a rule you need to follow: once you use asynchronous, the other function have to be asynchronous. i wonder you can modify like follow:

function onRequest(request, response) {
  var pathname = url.parse(request.url).pathname
  console.log('Request for ' + pathname + ' received.')

  response.writeHead(200, {'Content-Type': 'text/html'})
  run(pathname, function(res){ response.write(res)})  //changed
  response.end()
}

function run(pathname, callback) {
  switch(pathname) {
      case '/':
        callback('Welcome to my little test')
        break
      case '/time':
        callback('The time is ' + new Date().toLocaleTimeString())
        break
      case '/users':
        var response
        require('./mysql').getUsers(function(users) {
            console.log(users)
            callback(users) # changed
        })
        break
      default:
        callback('Unable to locate the requested page')
  }
}

http.createServer(onRequest).listen(port)
console.log('Server started on port ' + port + '.')

Upvotes: 0

Enrique Fueyo
Enrique Fueyo

Reputation: 3488

The way you could extract the value out of the callback is to assign that value to a variable out of the callback's scope, but I don't recommend you to do that since you would end up with lots of global variables, besides you don't know when the variable will be assigned. Try this and see what happens so you get some insight with how callbacks and node.js works:

function run(pathname) {
    switch(pathname) {
        case '/':
            response = 'Welcome to my little test'
            break
        case '/time':
            response = 'The time is ' + new Date().toLocaleTimeString()
            break
        case '/users':
            var response
            var out_of_callback_users
            require('./mysql').getUsers(function(users) {
                out_of_callback_users = users
                console.log("In the callback")
                console.log(users)
                response = users
            })
            console.log("After require");
            console.log(out_of_callback_users) //Users have not been assigned yet
            setTimeout(function(){
              console.log("In the timeout") 
              console.log(out_of_callback_users)
            },5000) //After 5 secs the query has been completed and users have been assigned.
            return response
            break
        default:
            response = 'Unable to locate the requested page'
    }
    return response
}

The way I would go is something like this:

function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname
    console.log('Request for ' + pathname + ' received.')

    response.writeHead(200, {'Content-Type': 'text/html'})
    run(pathname, function(response){
      response.write(response)
      response.end()
    })
}

function run(pathname,cb) {
    switch(pathname) {
        case '/':
            cb('Welcome to my little test');
            break;
        case '/time':
            cb('The time is ' + new Date().toLocaleTimeString());
            break;
        case '/users':
            require('./mysql').getUsers(function(users) {
                console.log(users);
                cb(users);
            })
            break;
        default:
            cb('Unable to locate the requested page');
    }
    return;
}

http.createServer(onRequest).listen(port)
console.log('Server started on port ' + port + '.')

Upvotes: 2

Related Questions