Return object from within Callback function - javascript

This question might sound duplicate of the one here but my scenario is quiet different. I have getSystemIds.js file like this:
var system_ids_list = {};
var getSystemIDs = function(req, callback) {
var client = //creating an object using internally developed node library
client.request('sql_parameter', {'Query.ID' : query_number},
function(err, req, res){
//Do some stuff to calculate necessary values
system_ids_list[key_value] = value_array;
i+= 1;
}
return(req, callback)
}
)
};
module.exports = getSystemIDs;
Now, as shown in the answer in the link above, I am doing this in app.js
appSSL.get('/sysids', function(req, res) {
var sys_ids = system_ids_list(req, function(err, sys_ids) {
res.render('sysids', sys_ids);
})
});
I am not getting any specific error but the web page never loads as if something is stuck in the process or it does not know where to go next. Can someone help me figure out what would be the best way to do this?

Your getSystemIds() function is never calling the callback that was passed to it so the caller of getSystemIds() never gets a result - thus nothing ever happens on the request.
Change it to this:
var system_ids_list = {};
var getSystemIDs = function (req, callback) {
var client = //creating an object using internally developed node library
client.request('sql_parameter', {'Query.ID': query_number}, function (err, req, res) {
//Do some stuff to calculate necessary values
system_ids_list[key_value] = value_array;
i += 1;
// call the callback now to communicate back the async results
callback(null, system_ids_list);
});
};
module.exports = getSystemIDs;
The way you have your code structured, system_ids_list will accumulate more and more values each time getSystemIDs() is called. That seems a bit of an odd way to structure things so I'm pointing that out in case that is not really what you intend.
Also, your getSystemIDs() function does not return anything so you should change this:
appSSL.get('/sysids', function(req, res) {
var sys_ids = system_ids_list(req, function(err, sys_ids) {
res.render('sysids', sys_ids);
});
});
to this to make it less missleading about what is going on:
appSSL.get('/sysids', function(req, res) {
system_ids_list(req, function(err, sys_ids) {
res.render('sysids', sys_ids);
});
});
And, if res.render() is from a system like ExpressJS, then you probably want to be passing an object and naming a template:
res.render('sometemplate.html', {sysids: sys_ids});
If you want system_ids_list to not accumulate values, but to return a fresh value each time, you can define it within your function like this:
var getSystemIDs = function (req, callback) {
var system_ids_list = {};
var client = //creating an object using internally developed node library
client.request('sql_parameter', {'Query.ID': query_number}, function (err, req, res) {
//Do some stuff to calculate necessary values
system_ids_list[key_value] = value_array;
i += 1;
// call the callback now to communicate back the async results
callback(null, system_ids_list);
});
};
module.exports = getSystemIDs;

Related

sails.js node.js Parse JSON on controller

In my controller called MapController I'm doing a function to do a parse of remote json files, and from an if-else structure add some values in an array called "parsewebservice", apparently everything is working fine but console.log ( parsewebservice); is not returning the values that were passed to the array "parsewebservice" in the place where it is returning it empty. But when I put it inside the forEach it returns, but everything cluttered and repeated then is not the right way.
I wanted to know why the values that were passed to the array "parsewebservice" are not going along with the variable after populada and what would be the correct way to do it?
Here is my code below:
/**
* MapController
*
* #description :: Server-side logic for managing Maps
* #help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
*/
module.exports = {
index: function(req, res, next) {
Data.find(function foundData(err, datas) {
if (err) return next(err);
var parsewebservice = [];
datas.forEach(function(data, index) {
var req = require("request");
var url = data.address + "?f=pjson";
req(url, function(err, res, retorno) {
if (err) {
console.log(err);
} else {
var camadas = JSON.parse(retorno);
if (camadas.mapName) {
camadas.layers.forEach(function(campo, i) {
if (campo.subLayerIds != null) {
} else if (campo.subLayerIds == null) {
parsewebservice.push([i, "dynamicMapLayer", campo.name, data.address]);
}
});
} else if (camadas.serviceDataType) {
parsewebservice.push([null, "imageMapLayer", camadas.name, data.address]);
} else if (camadas.type) {
parsewebservice.push([null, "featureLayer", camadas.name, data.address]);
}
}
});
});
console.log(parsewebservice);
});
},
};
My first comment has to be that you should not combine function(req, res) with var req = require('request')... you lose your access to the original req object!
So, you need to run a list of async tasks, and do something when they are all complete. That will never be entirely easy, and no matter what, you will have to get used to the idea that your code does not run from top to bottom as you've written it. Your console.log at the bottom runs before any of the callbacks (functions you pass in) you pass to your external requests.
The right way to do this is to use promises. It looks like you are using this request library, whose returned requests can only accept callbacks, not be returned as promises. You can create your own promise wrapper for them, or use an alternative library (several are recommended on the page).
I don't want to write a whole intro-to-promises right here, so what I will do is give you a less pretty, but maybe more understandable way to run some code at the completion of all your requests.
Data.find(function foundData(err, datas) {
if (err) return next(err);
var parsewebservice = [];
// here we will write some code that we will run once per returned data
var processResponse = function(resp) {
parsewebservice.push(resp);
if(parsewebservice.length >= datas.length) {
// we are done, that was the final request
console.log(parsewebservice);
return res.send({data: parsewebservice)}); // or whatever
}
};
datas.forEach(function(data, index) {
var request = require("request");
var url = data.address + "?f=pjson";
request(url, function(err, res, retorno) {
// do some processing of retorno...
// call our function to handle the result
processResponse(retorno);
});
});
console.log(parsewebservice); // still an empty array here
});
I solved the problem.
the "request" module is asynchronous so we need to wait for it to respond and then send the response to the view.
To do this we created a function called "foo" to contain the foreach and the request, we made a callback of that function and finally we made the response (res.view) within that function, so that the controller response would only be sent after the response of the "foo" function to the callback. So we were able to parse.json the data from the "data" collection using foreach and the "request" module and send the objects to the view.
Many thanks to all who have helped me, my sincere thanks.

Modularize functions between files in nodejs

I am miss understanding this concept in nodejs. I want to place a function in a folder at ./models/user lets say to represent a model I use for user. Then I want to use these as functions somewhere else. The issue I always run into is when do something like user.something it doesn't handle like a function. I am misunderstanding how this works.
The model would look something like this:
//model/user.js
function User() {
this.foo = null;
}
User.prototype.hashPass = function (password, callback) {
//Code that hashes a password
callback(err, hash);
};
User.prototype.insertUser = function (email, password, callback) {
//Code that inserts a user and returns some 'done' callback
callback(err, done);
};
module.exports = User;
And somewhere else in my program lets say passport.js I want to do this:
//config/passport.js
var User = require('../models/user);
var user = new User();
async.waterfall([
//how does this look
//EDIT ATTEMPTED HERE
user.hashPass(password, function(err, result) {
}),
user.insertUser(result, function(err, rows) {
})
], //some callback );
Made some edits to help to clarify what I am trying to accomplish here.
EDIT:
This link shows how to do async waterfalls with multiple callbacks
Code based on EDIT / Understanding:
async.series([
function(callback) {
user.hashPass(password, function(err, result) {
callback(err,result);
})
}
], function(err, result) {
if (err) return err;
console.log('test',result);
});
It's not working because you have to 'require' your module in the file you want to use it in and you're creating object methods on a constructor function that does not exist. Instead, you could create a user object (not a constructor function) and set each function to an object property, like this:
//module file
var user = {
hashPass: function(password, callback){
//password-hashing function
},
insertUser: function(email, password, callback){
//new user function
}
};
module.exports = user;
Then, in whatever place you want to use it, you do so like this:
//some other file
var user = require(path-to-module);
user.hashPass(); //pass in all parameters (password, callback)
user.insertUser(); //pass in all parameters (password, callback)
The only potential hang-up about this method is that you'll have to define all of your parameters before calling either object property.
The only thing you need to change in your code is to replace the line
module.exports = User;
in your passport.js file by
var User = require('../model/User');
Then you can invoke the functions on user:
user.hashPass(password, function(err, result) {
user.insertUser(result, function(err, rows) {
// do something with rows here
});
});
When we have been requiring custom modules we require them by path .
var User = require('config/passport');
var user = new User();
async.waterfall([
//how does this look
//do hashPass here
,
//do insertPass here
], //some callback );

NodeJS Variable outside function scope

For the life of me I cannot work this one out. Have look around and tried many many different ways of trying to get this to go. Currently have the following code.
var config = require("./config.js");
var cradle = require('cradle')
var MikroNode = require('mikronode');
var WebServer = require('./bin/www');
var Routers = "Hasnt changed";
var conndb = new(cradle.Connection)(config.couchdb.host);
var db = conndb.database(config.couchdb.db);
db.exists(function(err, exists){
if (err) { console.log('error', err);}
else if (exists) { console.log('Seems the Force is with you - Database Exists');}
else { db.create(); }
});
db.temporaryView({
map: function (doc){
if (doc.type=='ConfigRouter') emit(doc.name, doc);
}
}, function (err, res){
Routers = JSON.stringify(res);
}
);
console.log(Routers);
As it stands it will respond with:
E:\Dev\MM>npm start
> MM#0.0.1 start E:\Dev\MM
> node ./Start.js
Hasnt changed
Seems the Force is with you - Database Exists
I am assuming it is an asynchronous call to the CouchDB and is not filling the result in time before it displays the result. How do I get around this issue?
You are right, the call is asynchronous so when console.log(Routers); is processed, Routers is "Hasnt changed".
One way of doing it would be to use promises thanks to the Q npm module:
var Q = require('q');
var deferred = Q.defer();
db.temporaryView({
map: function (doc) {
if (doc.type=='ConfigRouter') emit(doc.name, doc);
}
}, function (err, res) {
deferred.resolve(JSON.stringify(res));
});
deferred.promise
.then(function (data) {
Routers = data;
console.log(Routers);
// do some stuff...
})
.done();
Maybe it's possible to do something better without using Q.defer and adapting directly the callback:
https://github.com/kriskowal/q#adapting-node

How to get a return value from asynchronous function in Node.js? [duplicate]

This question already has an answer here:
Why do I get an empty object when a function is invoked in node.js?
(1 answer)
Closed 8 years ago.
I want to get a return-value from this asynchronous function exports.getServices. But I just get nothing / null back.
var http = require("http");
var mysql = require('mysql');
var url = require("url");
var connection = mysql.createConnection({
...
});
connection.connect();
exports.getServices = function (){
connection.query('SELECT DISTINCT SERVICE FROM booking_count', function(err, rows, fields) {
if (err) throw err;
var services = new Array();
for (var i in rows) {
services[i] = rows[i].SERVICE;
}
return services;
});
}
I access this method from another module:
var express = require('express');
var hbs = require('express3-handlebars');
var app = express();
app.engine('html', hbs({defaultLayout: 'layout'}));
app.set('view engine', 'html');
app.set('views', __dirname + '\\views');
app.use(express.bodyParser());
var mysql = require('./mysql');
app.get('/', function(req, res) {
res.render('index',{title:"Services", services:mysql.getServices()});
});
app.get('/article/:id', function(req, res) {
var entry = blogEngine.getBlogEntry(req.params.id);
res.render('article',{title:entry.title, blog:entry});
});
app.listen(3000);
It would be very helpful if you could post a corrected code. Thank you very much in advance!
You don't provide any information about what module implements connection. Also, you don't make totally clear which function [getServices(), or the callback function passed to query()] is not returning anything. However, I will still try to answer your question.
The getServices() function never returns anything -- it just calls query(). So, obviously, you can't expect to get a result like this:
var result = getServices(...);
The callback function does return a value, but since it is the query() function that is calling it, there is no way for you to get that return value. Also, query() is probably ignoring any return value, anyway.
To fix this, you need to pass to getServices() your own callback function to receive the results. So, your implementation should look more like this:
connection.connect();
exports.getServices = function (next) {
connection.query('SELECT DISTINCT SERVICE FROM booking_count', function(err, rows, fields) {
if (err) throw err;
var services = new Array();
for (var i in rows) {
services[i] = rows[i].SERVICE;
}
next(services);
});
}
However, you should figure out if throwing an error (in the original callback, when there is an error) will cause problems (like causing your server to crash). You may want to do something else instead:
connection.connect();
exports.getServices = function (next) {
connection.query('SELECT DISTINCT SERVICE FROM booking_count', function(err, rows, fields) {
if (err) return next(err); // Pass err to next, and immediately return.
var services = new Array();
for (var i in rows) {
services[i] = rows[i].SERVICE;
}
next(null, services); // Pass result to next (with no error).
});
}
Welcome to the world of asynchronous functional programming!

NodeJS | Passing an object as function parameter

I've had a small problem I couldn't overcome this week, I'm trying to pass a JSON object as a parameter in a function but it always tells me that I can't do that, but I don't want to end up sending the 50 values separately from my json object.
Here is the set up on my app, this is working as intended with express :
app.get('/', routes.index);
Here is the routing index from the previous line of code (Note that I'm using jade for rendering and I'm using the next function to pass parameters to it like the name in this one :
exports.index = function(req, res){
getprofile.profileFunc(function(result) {
res.render('index', { name: result });
});
};
Next it calls the function profileFunc from getprofile :
var profileFunc = function(callback) {
var sapi = require('sapi')('rest');
sapi.userprofile('name_here', function(error, profile) {
var result = [profile.data.name];
callback.apply(null, result);
});
};
exports.profileFunc = profileFunc;
Note that I was only able to pass a string result and have it displayed in the jade render, what I want to do is pass the profile object to use it in the render to display name, age, birthday but I can't get it to work, it will either pass a undefined object or not pass.
Thanks for taking time to read this.
I'll suggest the following:
var profileFunc = function(callback) {
var sapi = require('sapi')('rest');
sapi.userprofile('name_here', function(error, profile) {
callback.apply(null, profile);
});
};
exports.profileFunc = profileFunc;
...
getprofile.profileFunc(function(result) {
res.render('index', result);
});
If you put an Object into Jade's template context, then you'll have to reference it using the variable containing that Object. In your templates, you'd access that using name.foo, name.bar, etc.
Actually the problem is with apply, apply takes array as second argument so when you are trying to send object its not working. Just use callback function without apply like this:-
var profileFunc = function(callback) {
var sapi = require('sapi')('rest');
sapi.userprofile('name_here', function(error, profile) {
callback(profile);
});
};
exports.profileFunc = profileFunc;
...
getprofile.profileFunc(function(result) {
res.render('index', result);
});

Categories

Resources