Nodejs Promises unusual behaviour with exec - node.js

i am executing the following code in nodejs and want an output like this :
and want an output like this
Running Code
Compiling Code
Executing Code
Done Execution
Done Compiling
Done everything
But the output is like this :
Running Code
Compiling Code
Executing Code
Done Execution
Done Compiling
Done everything
This is a strange behaviour :/
var sys = require('sys');
var exec = require('child_process').exec;
var Q = require('q');
var script_sh = 'bash -c' + ' "echo "hegr" ;"';
function compile(req, res) {
var deferred = Q.defer();
console.log('Compiling Code');
exec(script_sh, function puts(err, stdout, stderr) {
if (err || stderr) {
console.log('Error While Compiling');
console.log(err);
res.send(stderr || err );
return deferred.reject(err);
}
console.log('Done Compiling');
return deferred.resolve();
});
return deferred.promise;
}
function execute(req, res) {
console.log('Executing Code');
var deferred = Q.defer();
exec(script_sh, function puts(err, stdout, stderr) {
if (err || stderr) {
console.log('Error While Execution');
console.log(err || stderr);
res.send(err);
return deferred.reject(err || stderr);
}
console.log('Done Execution');
return deferred.resolve();
});
return deferred.promise;
}
function run_code(req,res) {
console.log('Running Code');
compile(req,res)
.then(execute(req,res))
.then(function() {
console.log('Done everything');
}).fail(function (error) {
error.status = 412;
return ;
});
};
module.exports = run_code;
(function() {
if (require.main == module) {
var req = console.log;
var res = console.log;
res.send = console.log;
run_code(req,res);
}
}());

You're not waiting for compile to resolve before invoking execute, but rather using the return value of execute as an argument to then, which happens to be a resolved Promise;
compile(req,res)
.then(execute(req,res))
The argument to then is evaluated when the body of the function run_code is evaluated, not when compile resolves. To wait for compile to resolve before executing execute, use:
compile(req, res)
.then(execute.bind(null, req, res));
execute.bind(null, req, res) will return a pre-bound function that will execute after compile resolves.
Alternatively,
compile(req, res)
.then(function () {
return execute(req, res);
});

Related

Node.js - undefined variable after assignment in fs functions

stackoverflow!
I am fairly new to node.js, and this seems to be node-specific. I keep defining a variable and I get errors that fileName is undefined. I have no idea why this is happening because, from my perspective, I'm just assigning a global variable inside a function, and that should work in all other programming languages I've worked in. Does the argument function in fs.readFile() somehow differ from a normal function? I honestly have no idea. Anyways, this is my full code:
var fs = require('fs');
var dateObject = new Date();
var fileName;
function Start() {
fs.readFile('./counter.txt', function (err, data) {
if (err) throw err;
var current = parseInt(data);
current++;
fs.writeFile('./counter.txt', current.toString(), function(err) {
if (err) throw err;
console.log("Written!");
});
var fullDate = `${dateObject.getDate()}-${dateObject.getMonth() + 1}-${dateObject.getFullYear()}`;
fileName = `./logs/${fullDate} ${current}.txt`;
console.log(fileName);
fs.appendFile(fileName, "Logger Initiated!", function(err){
if (err) throw err;
})
});
}
function PAL (text) {
if (fileName === undefined) {
console.log("...");
return "500";
}
console.log(fileName);
fs.appendFile(fileName, text, function(err) {
if (err) throw err;
})
}
module.exports = {Start, PAL};
Another file:
const logger = require('./logger')
// ....
app.listen(port, () => {
logger.Start();
logger.PAL("test");
})
You got an asynchronous trap in code, fs.readFile is an async function, so when you run .PAL, I think you expected .Start function done, but it's not true. Start function:
async function Start() {
return new Promise((resolve, reject) => {
fs.readFile('./counter.txt', function (err, data) {
if (err) throw reject(err);
var current = parseInt(data);
current++;
fs.writeFile('./counter.txt', current.toString(), function(err) {
if (err) reject(err);
console.log("Written!");
var fullDate = `${dateObject.getDate()}-${dateObject.getMonth() + 1}-${dateObject.getFullYear()}`;
fileName = `./logs/${fullDate} ${current}.txt`;
console.log("FILENAME: ", fileName);
fs.appendFile(fileName, "Logger Initiated!", function(err){
if (err) reject(err);
resolve();
})
});
});
})
}
Call: logger.Start().then(() => logger.PAL("test"));

Make exec wait for previous exec [duplicate]

I like to integrate exec from nodejs in a custom function to handle all the errors in this one function.
const exec = require('child_process').exec;
function os_func() {
this.execCommand = function(cmd) {
var ret;
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
ret = stdout;
});
return ret;
}
}
var os = new os_func();
This function returns undefined because exec isn't finished when the value returns.
How can i solve that? Can i force the function to wait for exec?
you can use promise as :
const exec = require('child_process').exec;
function os_func() {
this.execCommand = function (cmd) {
return new Promise((resolve, reject)=> {
exec(cmd, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
resolve(stdout)
});
})
}
}
var os = new os_func();
os.execCommand('pwd').then(res=> {
console.log("os >>>", res);
}).catch(err=> {
console.log("os >>>", err);
})
Since the command is executed asynchronously you will want to use a callback to handle the return value once the command has finished executing:
const exec = require('child_process').exec;
function os_func() {
this.execCommand = function(cmd, callback) {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
callback(stdout);
});
}
}
var os = new os_func();
os.execCommand('SomeCommand', function (returnvalue) {
// Here you can get the return value
});
Yet another solution using ES6 modules:
import fs from "node:fs";
import {exec} from "node:child_process";
import util from "node:util";
// promisify exec
const execPromise = util.promisify(exec);
try {
// wait for exec to complete
const {stdout, stderr} = await execPromise("ls -l");
} catch (error) {
console.log(error);
}
exec will deal with it in an async fashion, so you should receive a callback or return a promise.
One thing you could do in order to make it sync is to use execSync instead:
https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options
The child_process.execSync() method is generally identical to
child_process.exec() with the exception that the method will not
return until the child process has fully closed. When a timeout has
been encountered and killSignal is sent, the method won't return until
the process has completely exited. Note that if the child process
intercepts and handles the SIGTERM signal and doesn't exit, the parent
process will wait until the child process has exited.
Adding what worked for me, as none of the above did the trick!
const { exec } = require("child_process");
const util = require("util");
const execPromise = util.promisify(exec);
function parentFunction() {
...
// Trigger 'exec', then a-wait for it to finish
await execWrapper('<your-command-here>');
...
}
...
async function execWrapper(cmd) {
const { stdout, stderr } = await execPromise(cmd);
if (stdout) {
console.log(`stderr: ${stdout}`);
}
if (stderr) {
console.log(`stderr: ${stderr}`);
}
}
NOTE: This isn't your example, but just a generic one; for me - the cmd was a Docker build command. You could probably have execWrapper return back the stdout if needed.
You can do it with callback. Maybe you can try something like this:
function os_func() {
this.execCommand = function(cmd, myCallback) {
var ret;
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
ret = stdout;
myCallback(ret);
});
}
function myCallback(ret){
// TODO: your stuff with return value...
}

Nodejs - Await does not waits for the method to execute first

I am writing a function in nodejs to send print command to the macos. The problem is that my print command is sent successfully but I want to wait for the output received before moving forward.
My code is as follows
const printer = require("node-native-printer");
const exec = require("child_process").exec;
module.exports = {
print: async function (options) {
await this.printUnix(options).then(
response => {
return response
}
).catch(error => {
return false
});
},
printUnix: async function (options) {
if (!options.filePath)
return Error('File path not specified');
let command = 'lp ';
let unixOptions = [];
await Object.keys(options).forEach(value => {
switch (value) {
case 'duplex':
if (options[value] === 'Default')
command = command + '-o sides=one-sided ';
else
command = command + '-o sides=two-sided-short-edge ';
break;
case 'color':
if (options[value])
command = command + '-o blackplot ';
break;
case 'landscape':
if (options[value])
command = command + '-o orientation-requested=4 ';
else command = command + '-o orientation-requested=3 ';
break;
}
});
command = command + options.filePath;
return await this.executeQuery(command);
},
executeQuery: async function (command) {
exec(command, function (error, stdout, stderr) {
output = {stdout, error, stderr};
if (!stdout || stderr || error)
return false;
else
return true;
});
}
};
The problem here is that the function executeQuery is not executed completely and the result is returned i.e. undefined. How do I make my program wait for the function to execute properly?
executeQuery is not working as expected because you have mixed Async-Await with callbacks.
You cannot use Async-await syntax with callback. You have to promisify your callback function as below.
function(command){
return new Promise(resolve, reject){
exec(command, function (error, stdout, stderr) {
output = {stdout, error, stderr};
if (!stdout || stderr || error)
reject();
else
resolve();
})
}
}
Okay, it seems like this is wrong
await this.printUnix(options).then(
response => {
return response
}
).catch(error => {
return false
});
},
When you use async/await. you can't use promise callbacks .then or .catch (probably)
Try changing your code to something like this
print: async function (options) {
try {
return await this.printUnix(options)
} catch (error) {
return false
},

How to execute the file at different location in nodejs

I have to run file test.js which is at different location than the my running application. To do that i have tried the fallowing code
var execFile = require("child_process").execFile;
exports.sync = function(req, res) {
console.log("sync called");
var child = execFile("C:/Users/rhush/Desktop/test", function(error, stdout, stderr) {
if (error) {
throw error;
}
console.log(stdout);
res.send({ status: stdout });
});
};
and my test file is here :
function testing() {
console.log('sync job running');
}
testing();
but i got the error
please correct if i am doing any mistake.
To run a js file using execFile you need to pass node command with file name, Use this one:
var execFile = require("child_process").execFile;
exports.sync = function(req, res) {
console.log("sync called");
var child = execFile("node", ["C:/Users/rhush/Desktop/test.js"], function(error, stdout, stderr) {
if (error) {
throw error;
}
res.send({ status: stdout });
});
};

NodeJs Async Parallel: 'undefined is not a function'

I'm trying to wrap my head around the async library, but I'm pretty wobbly in NodeJs and I can't figure out async.parallel. The code below produces error TypeError: undefined is not a function on the line where the parallel tasks are to be executed. Am I correct in that tasks to be run in async.parallel should have a callback() when they are done? (irrelevant parts of the function are redacted)
function scrapeTorrents(url, callback) {
request(url, function(err, res, body) {
if(err) {
callback(err, null);
return;
}
var $ = cheerio.load(body);
var results = [];
var asyncTasks = [];
$('span.title').each(function(i, element){
// scrape basic info
var show = {title: info.title, year: info.year};
asyncTasks.push(
getOmdbInfo(show, function (err, res) {
if (res) {
omdbInfo = res;
results.push({
// add basic info and Omdb info
});
}
callback();
})
);
});
async.parallel(asyncTasks, function(){
callback(null, results);
});
});
}
In the section where you define async tasks, be sure to specify a closure with a parameter method to call once the task is complete (named differently than callback so as to avoid hoisting).
asyncTasks.push(
function (done) {
getOmdbInfo(show, function (err, res) {
if (err) {
return done(err);
}
if (res) {
omdbInfo = res;
results.push({
// add basic info and Omdb info
});
}
return done();
})
}
);

Resources