module.exports return value undefined - node.js

Little info, i have an arp.js file which takes a subnet address "192.168.2" and gets all strings returned from arp -a and stores in an array.
I can't figure out why my arpList function is returning an undefined value in my index.js file.
All the console.logs are returning the correct values in the arp.js page when called from the index.js, but the ipObj is coming up undefined. Even the console.log before i return of ipObj works.
Any help would be greatly appreciated.
var { spawn } = require('child_process');
const arpLs = spawn('arp', ['-a']);
var bufferData;
module.exports = {
arpList: function (subnet) {
arpLs.stdout.on('data', data => {
bufferData += data
})
arpLs.stderr.on('data', data => {
console.log('error: ' + data);
});
arpLs.on('exit', function (code) {
if (code != 0) {
console.log("Error exiting"); //if error occurs
}
console.log("exit start 1"); // checking internal processes at stages
var dataArray = bufferData.split(' ');
var ipArray = [];
for (i = 0; i < dataArray.length; i++) {
if (dataArray[i].includes(subnet)) {
ipArray.push(dataArray[i]);
console.log("loop working");
}
}
var ipObj = { "lanIps": ipArray };
console.log("Object is there: "+ipObj)
return ipObj; // this obj should be returned to the index.js call using
})
},
sayMyName: function () {
return "Hello";
}
}
//arpList(ipSubnet);
//INDEX.js
//the index page looks like this
//var arp = require('./arp.js);
//var ipSubnet = "192.168.2";
//var lanIps = arp.arpList(ipSubnet);
//console.log(lanIps);
I ended up adding a callback function to arpList - function (subnet, callback)
Then instead of returning the value pass it into the callback
Then on the index.js side instead of
var lanIps = arp.arpList(value)
i used
arp.arpList(value, function(res){lanIps = res}

return ipObj; // this obj should be returned to the index.js call using
It won't be returned. The reference say nothing about return value. Node-style callbacks rarely work like that because they are potentially asynchronous and returned value cannot be taken into account.
This a special case of this well-known problem. The process is asynchronous and is finished after arp.arpList(ipSubnet) call, there's nothing to assign to lanIps. This is a use case for promises. There are already third-party promisified counterparts like child-process-promise.
The problem can be also solved by moving to synchronous API. child_process functions have synchronous counterparts, including spawnSync.

Related

Q promise - how to use it?

I am new to Node and want to call a function and determine whether or not to call the next function based on the results of the first function. The functions are asynchronous so the results are not immediately known. The following code works fine but now I want to add more asynchronous functions and chain them all together.
var doSomething = require('./custom-module1.js'); //returns a boolean
var doAnotherThing = require('./custom-module2.js'); //returns a double
var var1 = process.argv[2];
var var2 = process.argv[3];
var var3 = process.argv[4];
doSomething(var1, var3, function(data) {
if (data) {
doAnotherThing(var1,var2, function(data){
console.log(var1 + ' is value: ' + data);
});
}
});
I want to make the code something like this using promises.
getListOfStuff()
.then(
for(i=0;i<data.length;i++) {
doSomething(data[i], var3)
.then(
if (doSomething returns true) {
doAnotherThing(data[i], var2)
.then(doYetAnotherThing(data[i]))
.then(andEvenMoreThingsToBeDone(data[i]))
}
);
}
);
I read about q and using denodefiy but I can't understand the syntax to make it work. Would it be best to modify my custom modules to return promises so they would be inherently thenable? I get the concept but not the syntax, how do I actually do it?
I tried to denodeify using the following 2 different notations.
var doSomethingDN = Q.denodeify(doSomething);
var doAnotherThingDN= Q.denodeify(doAnotherThing);
doSomethingDN(var1, var3)
.then(
if(!data) {
doAnotherThingDN(var1,var2)
}
);
And this one
var doSomethingDN = Q.nfbind(doSomething);
var doAnotherThingDN= Q.nfbind(doAnotherThing);
doSomethingDN (var1, var3)
.then(
if(!data) {
doAnotherThingDN(var1,var2)
}
);
The if get's an unexpected token error. If I remove then both run but the boolean result from doSomething isn't able to control the program flow.
You still need to use a callback function with promises:
doSomethingDN (var1, var3)
.then(function(data) {
// ^^^^^^^^^^^^^^^^
if (!data) {
return doAnotherThingDN(var1,var2)
}
}); /*
^
You were getting a syntax error because you put the function body right as the argument to then.

Nodejs run promises sequentially

Dears ,
How can i run promises in nodejs sequentially , in the following example am looping through array of hours then for each fetched hour get result from the database , the issue here : am getting results but i want it sequentially same order that i got hours .
angular.forEach(SharedVar.getCategories(), function (h) {
t = h.split('-', 2);
t = t[0];
RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {
$scope.answerdCallsTotalByHour.push(answerdTotal);
var d = SharedVar.getDataS();
d[count] = answerdTotal;
SharedVar.setDataS(d);
count++;
});
});
Thanks ,
var promise = Promise.resolve(); // make an empty promise in the way you do it with your promise library
angular.forEach(SharedVar.getCategories(), function (h) {
promise.then(function() {
return RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {});
});
});
The way to do it sequently would be to do one Request and do the next request inside the promise.
I think the better approach by far is to extend your SharedVar.setDataS(d) function in a way, that it does not depend on getting the data sequentially. Like having a SharedVar.setDataS(d, index) and using the config var in your $http.get (or whatever) functioncall inside your RESTApi to promote that index all the way to the promise.
If your RESTApi looks like this:
var RESTApi = {
getAnswerdCallsByHour : function(hour) {
var url = "bla.com/myservice?hour=" + hour;
return $http.get(url).data;
}
// Some other Methods...
Then you need a way to pass something to "reorder" your Data when it arrives asynchronously, this could be a index you count up or in your case maybe the hour Variable:
var RESTApi = {
getAnswerdCallsByHour : function(hour) {
var url = "bla.com/myservice?hour=" + hour;
var config = [];
config.hour = hour;
return $http.get(url, config); // Return the promise not just data or a specific field
}
// Some other Methods...
Now when your promise is fullfiled you can access your "hour" Variable like so:
var d = SharedVar.getDataS();
d[promise.config.hour] = promise.data;
SharedVar.setDataS(d);
Now you know what piece of data correlates to which request and you do not need to recieve Data in order. The last piece only works properly when hours runs sequential from 0 to 23, if that isn't the case you need to:
var RESTApi = {
getAnswerdCallsByHour : function(hour, index) {
var url = "bla.com/myservice?hour=" + hour;
var config = [];
config.index = index;
return $http.get(url, config);
}
// Some other Methods...
...
...
var d = SharedVar.getDataS();
d[promise.config.index] = promise.data;
SharedVar.setDataS(d);
Safari's answer is how I typically handle this. (Sorry, I don't have enough rep to comment yet...) You were experiencing problems with it because the example provided does not capture and use the new promise in subsequent loops. See my comments on the slightly modified version here:
var promise = Promise.resolve();
angular.forEach(SharedVar.getCategories(), function (h) {
t = h.split('-', 2);
t = t[0];
// You must capture the new promise here; the next loop will wait
// for the promise returned from getAnswerdCallsByHour to resolve.
promise = promise.then(function() {
// Halt downstream promises until this returned promises finishes
return RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {
$scope.answerdCallsTotalByHour.push(answerdTotal);
var d = SharedVar.getDataS();
d[count] = answerdTotal;
SharedVar.setDataS(d);
count++;
});
});
});

Nodejs: Resolving promises with generator function

I know there are a lot of good examples over the web and I read a lot of them, but currently I'm stucked with resolving promises with the new functionality of generators in nodejs 0.11.x.
For e.g. I have the following function:
SolrBaseDomain.prototype.promisedQuery = function(query, callback) {
var solrClient = solr.createClient(this.configuration);
var defer = Q.defer();
solrClient.search(query, function(err,obj){
if (!err) {
if (obj.response.numFound > 0) {
defer.resolve(obj.response.docs);
} else {
defer.resolve(null);
}
} else {
defer.reject(err);
}
});
var promise = defer.promise;
return Q.async(function* (){
var result = yield promise;
return result;
});
};
I expected that every call to this method will wait until the promise is fullfilled and the return-statement gives back the result of the promise.
But currently it seems that instead the code inside "Q.async..." will not be executed or the async call arrives after the return statement of the method was executed.
It's strange, in every example I know, this is one of the recommended ways in order to wait for async calls in nodejs but currently it does not work for me.
I've tried a lot of different variations of the above example, but the result is everytime the same, I get not back a valid result.
I have nodejs installed in version 0.11.10 and the --harmony-flag is set, when the code is executede.
Can anyone point me to right direction? I'm wondering if I oversee something ... :)
Thanks for your feedback.
Best regards
Udo
I expected that every call to this method will wait until the promise is fullfilled and the return-statement gives back the result of the promise.
No. Generators will not make functions synchronous, you cannot (and don't want to) block while waiting for a result. When calling a generator function and running sequentially through the async steps that it yields, the result you will get back in the end is still asynchronous - and therefore a promise. Only inside of the generator, your code can use synchronous control flow and yield.
This means that the (then-) callback-based code
SolrBaseDomain.prototype.promisedQuery = function(query) {
var promise = Q.ninvoke(solr.createClient(this.configuration), "search", query);
return promise.then(function(obj) {
if (obj.response.numFound > 0) {
return obj.response.docs;
} else {
return null;
}
});
};
becomes
SolrBaseDomain.prototype.promisedQuery = Q.async(function* (query) {
var promise = Q.ninvoke(solr.createClient(this.configuration), "search", query);
var obj = yield promise;
// ^^^^^
if (obj.response.numFound > 0) {
return obj.response.docs;
} else {
return null;
}
});
Try this
SolrBaseDomain.prototype.promisedQuery = Q.async(function*(query) {
var solrClient = solr.createClient(this.configuration);
var obj = yield Q.ninvoke(solrClient, "search", query);
return obj.response.numFound > 0 ? obj.response.docs : null;
});
This does the same thing for promises as this does for callbacks:
SolrBaseDomain.prototype.query = function (query, callback) {
var solrClient = solr.createClient(this.configuration);
solrClient.search(query, function(err, obj) {
if (err) return callback(err);
callback(null, obj.response.numFound > 0 ? obj.response.docs : null);
});
};
Therefore if the first return a promise that resolves to undefined so will the callback version call the callback with undefined.
according to your suggestions, my code looks now like this:
...
SolrBaseDomain.prototype.query = Q.async(function* (query) {
var solrClient = solr.createClient(this.configuration);
var obj = yield Q.ninvoke(solrClient, "search", query);
return obj.response.numFound > 0 ? obj.response.docs : null;
});
...
I share the above query-function over all data access layers in order to have a central method which is querying the different indexes in an asynchronous way.
For e.g. in the domain data access layer, the code which deals with that function looks like this:
SolrHostDomain.prototype.getByName = Q.async(function* (domain) {
var queryObject = {
"domain": domain
};
var query = this.getQuery("byName", queryObject);
var docs = yield this.query(query);
var domain = null;
if (docs != null && docs.length > 0) {
domain = this.dataMapper.merge(docs[0]);
}
return domain;});
Currently I'm not sure if the generator in the "getByName"-function is necessary, but it seems to work. Dealing with promises is some unclear concept for me, since I'm new to nodejs.
So maybe, if you can help me on that topic and point me in the right direction, this would be helpfull.
The main question for me is, how can I ensure, that a synchronous method can call an asynchronous method and get back not a promise but the final result of this promise.
I've searched a long time, but I could not find a good documentation which describes the use of generator functions or promises in conjunction with synchronous calls. Even examples are focusing only of using the mechanism but not working together with synchronous function.
Best regards and many thanks for your help
Udo
Got it!!!
After a few trial and errors, I think I got it now and I have a working solutions:
Query function:
SolrBaseDomain.prototype.query = Q.async(function* (query) {
var solrClient = solr.createClient(this.configuration);
var obj = yield Q.ninvoke(solrClient, "search", query);
return obj.response.numFound > 0 ? obj.response.docs : null;
});
Calling method:
SolrHostDomain.prototype.getByName = function(domain) {
var queryObject = {
"domain": domain
};
var query = this.getQuery("byName", queryObject);
var docsPromise = this.query(query);
var _self = this;
return docsPromise.then(function(docs) {
var domain = null;
if (docs != null && docs.length > 0) {
domain = _self.dataMapper.merge(docs[0]);
}
return domain;
});
};
The solution was to understand, that the "query"-method still returns a promise instead of the concrete result even if yield is used.
So I have to add every code which is working on the result of the promise within the "then"-functions (or "done" if no other caller up in the calling hierarchy of methods will follow).
After the settlement of the promise, each code which is set within the "then"-functions will be processed.
BR
Udo

Node.js, Synchronize.js and return values

I'm using this wonderful sync module, synchronize.js - http://alexeypetrushin.github.io/synchronize/docs/index.html.
I've run into a situation where I have to get the return value of the sync'd function into the scope outside of the fiber. Here's a basic example of what I'm talking about:
var records = sync.fiber(function() {
var results = ... // some synchronized function
return results;
});
Whereas records would, in theory, contain the value of resultsfrom within the fiber scope. I've been reading up on futures (fibers/futures module) and how they might be used in this situation but I have yet to come up with anything close to working. I'd love some direction and/or a solution.
edit:
For a more thorough example of what I'm looking to accomplish:
// executes a stored procedure/function
exec: function (statement, parameters) {
init();
var request = new sql.Request(),
results;
processParams(parameters, request);
var res = sync.fiber(function(){
try {
var result = sync.await(request.execute(statement, sync.defers('recordsets', 'returnValue')));
results = result.recordsets.length > 0 ? result.recordsets[0] : [];
return results;
}
catch (e) {
console.log('error:connection:exec(): ' + e);
throw(e);
}
});
// though typical scope rules would mean that `results` has a
// value here, it's actually undefined.
// in theory, `res` would contain the return value from the `sync.fiber` callback
// which is our result set.
return res;
}
As you can see here, what I'd like to accomplish is to get the value of results in the primary scope, from the fiber's scope.
Now it does support it, use following form
var records = sync.fiber(function() {
var results = ... // some synchronized function
return results;
}, function(err, results){... /* do something with results */});
It's not a scope problem. This wont work because return res; executes before the fiber returns. That is why it's undefined.
You need to rewrite your exec function to take a callback. Then you could use synchronize.js on the exec function itself.

Retrieve stdout to variable

I’m trying to run child process in next code:
run = function (cmd, callback) {
var spawn = require('child_process').spawn;
var command = spawn(cmd);
var result = '';
command.stdout.on('data', function (data) {
result += data.toString();
});
command.on('exit', function () {
callback(result);
});
}
execQuery = function (cmd) {
var result = {
errnum: 0,
error: 'No errors.',
body: ''
};
run(cmd, function (message) {
result.body = message;
console.log(message);
});
return result;
}
After execution execQuery('ls') result.body is always empty, but console.log is contain value.
I ran a quick test and the command's exit event is firing before all of stdouts data is drained. I at least got the output captured and printed if I changed your exit handler to look for command.stdout's end event.
command.stdout.on('end', function () {
callback(result);
});
That should help a bit. Note there are existing libraries you might want to use for this and a truly correct implementation would be significantly more involved than what you have, but my change should address your current roadblock problem.
Random tip: it is the node convention to always reserve the first argument of callback functions for an error and your snippet is inconsistent with that convention. You probably should adjust to match the convention.
Oh sorry, let me address your question about result.body. The run function is ASYNCHRONOUS! That means that your return result; line of code executes BEFORE the run callback body where result.body = message; is. You can't use return values like that anywhere in node when you have I/O involved. You have to use a callback.

Resources