Node.js: Object value as stdout of child_process.exec - node.js

I'm new to Node and stumbling on some of the nonblocking elements of it. I'm trying to create a object and have one of the elements of it being a function that returns the stdout of a child_process.exec, like so:
var exec = require('child_process').exec;
var myObj = {};
myObj.list = function(){
var result;
exec("ls -al", function (error, stdout, stderr) {
result = stdout;
});
return result;
}
console.log('Ta da : '+myObj.list);
I figure that myObj.list is returning result before it is set as stdout, but I can't figure out how to make it wait or do a callback for it. Thanks for your help!

You can't directly return the value as it's not going to be available for a bit. So instead of a return value you need to use a callback which means turning the calling code inside out a bit.
var exec = require('child_process').exec;
var myObj = {};
myObj.list = function(callback){
var result;
exec("ls -al", function (error, stdout, stderr) {
callback(stdout);
});
// No return at all!
}
// Instead of taking a return we pass a callback
// which receives the value and carries on our computation.
myObj.list(function (stdout) {
console.log('Ta da : '+ stdout);
});
In real code you'd probably want to have your callback take an error as its first argument, you don't have to but it's the normal way things are done in Node.JS.

Related

Node.JS - Node-PowerShell return value

I am using a node-powershell module from https://www.npmjs.com/package/node-powershell.
var shell = require('node-powershell');
PS = new shell('echo "node-powershell is awesome"');
PS.on('output', function(data){
console.log(data);
});
PS.on('end', function(code) {
//optional callback
//Do Something
});
I am trying to return data from a function and assign it to a variable $returneddata:
function getData()
{
var shell = require('node-powershell');
PS = new shell('echo "node-powershell is awesome"', {debugMsg: false});
PS.on('output', function(data){
return data;
});
PS.on('end', function(code) {
});
}
var $returneddata = getData();
But it does not assign it.
You are not seeing the data because your return statement is returning it to the wrong caller :) PS.on('output' ... is registering a callback function for an event. The provided function will then be called by the event emitter when the event is raised. Therefore, the value returned by this callback is actually being returned to the event emitter, who doesn't care about your return value, rather than the caller of getData.
To correct the issue, you should provide a callback of your own, try this:
function getData(callback) {
var shell = require('node-powershell');
PS = new shell('echo "node-powershell is awesome"', {debugMsg: false});
PS.on('output', function(data){
return callback(null, data);
});
PS.on('end', function(code) {
});
}
getData(function onGetData(err, data) {
// do stuff with the returned data here
});
As an aside, you may not need the err parameter, but error-first callbacks are the convention in node. You should probable add PS.on('error' ... if the module supports it...

How can I make the results of a csv file-to-multidimensional array available globally?

If I have a global array:
var people = [];
And I have the following function:
function readFile() {
var IN = require('ya-csv');
var filePath = 'data.csv';
var reader = IN.createCsvFileReader(filePath, {
'separator': ','
});
reader.on('data', function(item) {
people.push(item);
});
}
The people array only seems scoped inside reader.on. How can I use the people array globally?
Your code is perfectly right if the people variable is declared outside the readFile function, which seems to be the case.
I guess that your problem is something like this:
var people = [];
function readFile() {
var IN = require('ya-csv');
var filePath = 'data.csv';
var reader = IN.createCsvFileReader(filePath, {
separator: ',' // quotes around property name are optional
});
reader.on('data', function(item) {
people.push(item);
});
}
readFile();
console.log(people); // <- people is empty
This behaviour is absolutely normal. As ya-csv process incoming data asynchronously, you have to wait for processing to be finished.
That's the purpose of the end event, triggered by CsvReader when it has finished (unfortunately not documented on ya-csv documentation)
Refactoring like this will work better:
// make filePath a parameter, and use a callback function
function readFile(filePath, callback) {
// make people scoped to readFile()
var people = [];
var IN = require('ya-csv');
var reader = IN.createCsvFileReader(filePath, {
separator: ',' // quotes around property name are optional
});
// data is emitted for each processed line
reader.on('data', function(item) {
// closure magic: people is accessible because current function is nested into readFile()
people.push(item);
});
// end event
reader.on('end', function() {
// return results to caller, simply by invoking the callback.
// by convention, first argument is an error, which is null it no problem occured
callback(null, people);
});
// error handling
reader.on('error', function(err) {
// stop listening on events, to avoid continuing queuing data
reader.removeAllListeners();
// report to caller the error.
callback(err);
}
}
readFile('data.csv', function(err, results) {
if (err) {
// error handling
return ...
}
// nominal case: use results that contains peoples !
console.dir(results);
});
Please ask question with comments if something is not clear.
== EDIT ==
Alternatively, you can use a variable outside readFile()
// notice: people is declared outside readFile
var people = []
// make filePath a parameter, and use a callback function
function readFile(filePath, callback) {
var IN = require('ya-csv');
var reader = IN.createCsvFileReader(filePath, {
separator: ',' // quotes around property name are optional
});
// data is emitted for each processed line
reader.on('data', function(item) {
// closure magic: people is accessible because current function is nested into readFile()
people.push(item);
});
// end event: directly invoke callback
reader.on('end', callback);
// error handling
reader.on('error', function(err) {
// stop listening on events, to avoid continuing queuing data
reader.removeAllListeners();
// report to caller the error.
callback(err);
}
}
readFile('data.csv', function(err) {
if (err) {
// error handling
return ...
}
// you cannot use people before here, because you have no garantie that read process is finished.
console.dir(people);
});
The drawback of this code is that calling readFile() multiple times will enqueue in the same variable, which is not modular nor reliable.

how to wait the end of the execution of a function

I have a main in nodejs for my program where I need to use my result calculated in a module, but my I don't have the right result.
var myJSONClient = {
"nombre" : "<nombre_cliente>",
"intervalo" : [0,0]
};
var intervalo = gestionar.gestion(myJSONClient,vector_intervalo);
console.log("intervalo: "+intervalo); //return undefined
And this is the module
var gestion = function(myJSON,vector_intervalo) {
var dburl = 'localhost/mongoapp';
var collection = ['clientes'];
var db = require('mongojs').connect(dburl, collection );
var intervalo_final;
function cliente(nombre, intervalo){
this.nombre = nombre;
this.intervalo = intervalo;
}
var cliente1 = new cliente(myJSON.nombre,myJSON.intervalo);
db.clientes.save(cliente1, function(err, saveCliente){
if (err || !saveCliente) console.log("Client "+cliente1.nombre+" not saved Error: "+err);
else {
console.log("Client "+saveCliente.nombre+" saved");
intervalo_final = calculate(vector_intervalo);
console.log(intervalo_final); //here I can see the right content of the variable intervalo_final
}
});
setTimeout(function(){
console.log("pause");
},3000);
console.log(intervalo_final); //result not correct
return intervalo_final;
}
exports.gestion = gestion;
I know that node execute my return without wait the end of my function, for this I can't see the right result, but how can I force my program to wait the end of my function?
I tried with the setTimeout function but wasn't the right way.
You must implement your function just like the other async functions from the API!
First step : give callback to function
var gestion = function(myJSON,vector_intervalo, callback) {
Second step : when the async process is over call callback passing the result (you don't need the return line)
console.log(intervalo_final); //here I can see...
callback(intervalo_final);
Step three: use your function in an async way
gestionar.gestion(myJSONClient,vector_intervalo, function(result){
console.log(result);
});
In async JS you can't return a value the way it seems you trying to do. You need to pass a callback function from your main program when calling gestionar.gestion() (you can add it as a third argument).
Your code sample won't work because function gestion() returns immediately, before intervalo_final content is set.
Something like this:
gestionar.gestion(myJSONClient,vector_intervalo, function callback(intervalo) {
// This is the callback function
console.log("intervalo: " + intervalo);
});
And then within the function:
var gestion = function(myJSON,vector_intervalo, callback) {
...
db.clientes.save(cliente1, function(err, saveCliente) {
if (err || !saveCliente) {
console.log("Client "+cliente1.nombre+" not saved Error: "+err);
if (callback) callback(); // execute callback function without arguments
}
else {
console.log("Client "+saveCliente.nombre+" saved");
intervalo_final = calculate(vector_intervalo);
console.log(intervalo_final);
if (callback) callback(intervalo_final); // your callback function will be executed with intervalo_final as argument
}
});
Also, I highly recommend reading some async javascript tutorial, like http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/
And Felix's Node.js Guide: http://nodeguide.com/

Node.js: how to pass a readStream as function argument and use in a callback?

I want to pass a stream as argument to a function and use it in an async callback but it is destroyed (stream.readable is false)
for example:
var test = require('./test');
var file = fs.createReadStream('./file.txt');
test(file, console.log);
and in test.js:
module.exports = function(stream, callback) {
//stream.pipe(process.stdout); ///////// STREAM IS READABLE HERE
doSomething('abc', function(err) {
stream.pipe(process.stdout); ///////// STREAM IS NOT READABLE HERE
callback(err);
});
};
enter code here
why is this happening ?
what can I do to use it in the callback ?
This happens because stream ends before you trying to pipe it. In the first place stream is readable because you synchronous code still working. In the second place (inside of callback) stream already ended because callback may be executed after several ticks in future. You need to pasue your streem if you want to read it in future. This code should work:
var test = require('./test');
var file = fs.createReadStream('./file.txt');
file.pause();
test(file, console.log);
test.js
module.exports = function(stream, callback) {
doSomething('abc', function(err) {
stream.resume();
stream.pipe(process.stdout);
callback(err);
});
};

Async utility for Node.js Call back function not executing

I am trying to use the async utility for the node.js. Below is my code. The console prints "In my func1" and "In my func2". I also expect it to print "call back func" but it won'nt
var myfunc1 = function(callback) {
var a = 1;
console.log ("In my func1");
};
var myfunc2 = function(callback) {
var b = 2;
console.log ("In my func2");
};
models.Picture.prototype.relativeSort = function(viewer_location) {
console.log("Rel Sort");
var sortedPics = [];
var relsortedPics = [];
// Finds all the pictures
async.series([myfunc1(), myfunc2()],
function(err, results){
if(err) {
throw err;
}
console.log("call back func");
return a+b;
});
};
You need to use the callback argument, for example:
var myfunc1 = function(callback) {
var a = 1;
console.log ("In my func1");
callback(null, 'test');
};
The first argument of callback is an error, and the second the result you want to pass to the final handler.
EDIT
I've missed the other mistake. This line:
async.series([myfunc1(), myfunc2()],
should be
async.series([myfunc1, myfunc2],
You are not supposed to call functions. You are telling async: "Hey, take these functions and do something (asynchronous) with them!".

Resources