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
},
Related
Hi guys, I'm newbie in node.js. I have function, that leads the dialogue with user in console. In newSwagger function I call the bumpDiff function, that shows changes between 2 files.
async function bumpDiff = () => {
exec('bump diff swagger.json newSwagger.json', (err, output) => {
// once the command has completed, the callback function is called
if (err) {
// log and return if we encounter an error
console.error("could not execute command: ", err)
return
}
// log the output received from the command
console.log("Output: \n", output)
})
};
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const question = (str) => new Promise(resolve => rl.question(str, resolve));
const steps = {
start: async () => {
return steps.changeSwagger();
},
changeSwagger: async () => {
const addSwagger = await request();
console.log('success');
const changeSwagger = await question("Would you like to check changes in swagger? Please type yes/no: ");
if (changeSwagger === 'yes') { return steps.newSwagger(); }
if (changeSwagger === 'no') { return steps.oldSwagger(); }
return steps.end();
},
newSwagger: async () => {
console.log('showing changes');
const diff = await bumpDiff();
const ask = await question('Would you like to change swagger? Please type yes/no: ');
if (ask === 'yes') { return steps.changing(); }
if (ask === 'no') { return steps.end(); }
},
changing: async () => {
const rebuildSwagger = await SwaggerNew();
console.log('swagger changed successfully');
return steps.end();
},
oldSwagger: async () => {
console.log('No worries, have a nice day');
return steps.end();
},
end: async () => {
rl.close();
},
};
steps.start();
The problems is: when bumpDiff is starting, next readline
'Would you like to change swagger? Please type yes/no: '
come faster, then changes appeares. I guess I'm missing something about promises, can you help me find the mistake please.
P.S. all other functions, like 'request' and 'SwaggerNew' are async.
You are mixing two "styles" the callback approach in the "exec" function and you are trying to await that bumpDiff that is not returning a Promise (async/await approach), take a look to utils.Promisify helper function.
From NodeJS docs:
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);
async function lsExample() {
const { stdout, stderr } = await exec('ls');
console.log('stdout:', stdout);
console.error('stderr:', stderr);
}
lsExample();
You need to turn the callback style exec call into a promise so that await bumpDiff() can work properly.
async function bumpDiff = () => {
return new Promise((resolve, reject) => {
exec('bump diff swagger.json newSwagger.json', (err, output) => {
if (err) {
console.error("could not execute command: ", err)
reject(err)
} else {
console.log("Output: \n", output)
resolve(output)
}
})
})
};
I'm using the Bluebird promise library under Node.js, it's great! But I have a question:
If you take a look at the documentation of Node's child_process.exec and child_process.execFile you can see that both of these functions are returning a ChildProcess object.
So what's the recommended way to promisify such functions?
Note that the following works (I get a Promise object):
var Promise = require('bluebird');
var execAsync = Promise.promisify(require('child_process').exec);
var execFileAsync = Promise.promisify(require('child_process').execFile);
But how can one get access to the original return value of the original Node.js functions? (In these cases I would need to be able to access the originally returned ChildProcess objects.)
Any suggestion would be appreciated!
EDIT:
Here is an example code which is using the return value of the child_process.exec function:
var exec = require('child_process').exec;
var child = exec('node ./commands/server.js');
child.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function(data) {
console.log('stderr: ' + data);
});
child.on('close', function(code) {
console.log('closing code: ' + code);
});
But if I would use the promisified version of the exec function ( execAsync from above ) then the return value will be a promise, not a ChildProcess object. This is the real problem I am talking about.
I would recommend using standard JS promises built into the language over an additional library dependency like Bluebird.
If you're using Node 10+, the Node.js docs recommend using util.promisify which returns a Promise<{ stdout, stderr }> object. See an example below:
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function lsExample() {
try {
const { stdout, stderr } = await exec('ls');
console.log('stdout:', stdout);
console.log('stderr:', stderr);
} catch (e) {
console.error(e); // should contain code (exit code) and signal (that caused the termination).
}
}
lsExample()
Handle errors first from stderr.
It sounds like you'd like to return two things from the call:
the ChildProcess
a promise that resolves when the ChildProcess completes
So "the recommended way to promisify such functions"? Don't.
You're outside the convention. Promise returning functions are expected to return a promise, and that's it. You could return an object with two members (the ChildProcess & the promise), but that'll just confuse people.
I'd suggest calling the unpromisified function, and creating a promise based off the returned childProcess. (Maybe wrap that into a helper function)
This way, it's quite explicit for the next person who reads the code.
Something like:
var Promise = require('bluebird');
var exec = require('child_process').execFile;
function promiseFromChildProcess(child) {
return new Promise(function (resolve, reject) {
child.addListener("error", reject);
child.addListener("exit", resolve);
});
}
var child = exec('ls');
promiseFromChildProcess(child).then(function (result) {
console.log('promise complete: ' + result);
}, function (err) {
console.log('promise rejected: ' + err);
});
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
child.on('close', function (code) {
console.log('closing code: ' + code);
});
If you're just wanting to promisify specifically child_process.exec() and child_process.execFile(), in recent node versions there is a better answer here.
Since Node v12 the built-in util.promisify allows access to the ChildProcess object in the returned Promise for built-in functions where it would have been returned by the un-promisified call. From the docs:
The returned ChildProcess instance is attached to the Promise as a child property.
This correctly and simply satisfies the need to access ChildProcess in the original question and makes other answers out of date providing that Node v12+ can be used.
Adapting the example (and concise style) provided by the questioner, access to the ChildProcess can be achieved like:
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const promise = exec('node ./commands/server.js');
const child = promise.child;
child.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function(data) {
console.log('stderr: ' + data);
});
child.on('close', function(code) {
console.log('closing code: ' + code);
});
// i.e. can then await for promisified exec call to complete
const { stdout, stderr } = await promise;
Here's another way:
function execPromise(command) {
return new Promise(function(resolve, reject) {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
resolve(stdout.trim());
});
});
}
Use the function:
execPromise(command).then(function(result) {
console.log(result);
}).catch(function(e) {
console.error(e.message);
});
Or with async/await:
try {
var result = await execPromise(command);
} catch (e) {
console.error(e.message);
}
There's probably not a way to do nicely that covers all use cases. But for limited cases, you can do something like this:
/**
* Promisified child_process.exec
*
* #param cmd
* #param opts See child_process.exec node docs
* #param {stream.Writable} opts.stdout If defined, child process stdout will be piped to it.
* #param {stream.Writable} opts.stderr If defined, child process stderr will be piped to it.
*
* #returns {Promise<{ stdout: string, stderr: stderr }>}
*/
function execp(cmd, opts) {
opts || (opts = {});
return new Promise((resolve, reject) => {
const child = exec(cmd, opts,
(err, stdout, stderr) => err ? reject(err) : resolve({
stdout: stdout,
stderr: stderr
}));
if (opts.stdout) {
child.stdout.pipe(opts.stdout);
}
if (opts.stderr) {
child.stderr.pipe(opts.stderr);
}
});
}
This accepts opts.stdout and opts.stderr arguments, so that stdio can be captured from the child process.
For example:
execp('ls ./', {
stdout: new stream.Writable({
write: (chunk, enc, next) => {
console.log(chunk.toString(enc));
next();
}
}),
stderr: new stream.Writable({
write: (chunk, enc, next) => {
console.error(chunk.toString(enc));
next();
}
})
}).then(() => console.log('done!'));
Or simply:
execp('ls ./', {
stdout: process.stdout,
stderr: process.stderr
}).then(() => console.log('done!'));
Just want to mention that there's a nice tool that will solve your problem completely:
https://www.npmjs.com/package/core-worker
This package makes it a lot easier to handle processes.
import { process } from "CoreWorker";
import fs from "fs";
const result = await process("node Server.js", "Server is ready.").ready(1000);
const result = await process("cp path/to/file /newLocation/newFile").death();
or combine these functions:
import { process } from "core-worker";
const simpleChat = process("node chat.js", "Chat ready");
setTimeout(() => simpleChat.kill(), 360000); // wait an hour and close the chat
simpleChat.ready(500)
.then(console.log.bind(console, "You are now able to send messages."))
.then(::simpleChat.death)
.then(console.log.bind(console, "Chat closed"))
.catch(() => /* handle err */);
Here are my two cents. Uses spawn which streams the output and writes to stdout and stderr. The error and standard output is captured in buffers and are returned or rejected.
This is written I Typescript, feel free to remove typings if using JavaScript:
import { spawn, SpawnOptionsWithoutStdio } from 'child_process'
const spawnAsync = async (
command: string,
options?: SpawnOptionsWithoutStdio
) =>
new Promise<Buffer>((resolve, reject) => {
const [spawnCommand, ...args] = command.split(/\s+/);
const spawnProcess = spawn(spawnCommand, args, options);
const chunks: Buffer[] = [];
const errorChunks: Buffer[] = [];
spawnProcess.stdout.on("data", (data) => {
process.stdout.write(data.toString());
chunks.push(data);
});
spawnProcess.stderr.on("data", (data) => {
process.stderr.write(data.toString());
errorChunks.push(data);
});
spawnProcess.on("error", (error) => {
reject(error);
});
spawnProcess.on("close", (code) => {
if (code === 1) {
reject(Buffer.concat(errorChunks).toString());
return;
}
resolve(Buffer.concat(chunks));
});
});
Just another example you might run into issues when running multiple commands when destructuring with the same const's you can rename them like this.
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function runCommands() {
try {
const { stdout, stderr } = await exec('ls');
console.log('stdout:', stdout);
console.log('stderr:', stderr);
const { stdout: stdoutTwo, stderr: stderrTwo } = await exec('ls');
console.log('stdoutTwo:', stdoutTwo);
console.log('stderrTwo:', stderrTwo);
const { stdout: stdoutThree, stderr: stderrThree } = await exec('ls');
console.log('stdoutThree:', stdoutThree);
console.log('stderrThree:', stderrThree);
} catch (e) {
console.error(e); // should contain code (exit code) and signal (that caused the termination).
}
}
runCommands()
Here's mine. It doesn't deal with stdin or stdout, so if you need those then use one of the other answers on this page. :)
// promisify `child_process`
// This is a very nice trick :-)
this.promiseFromChildProcess = function (child) {
return new Promise((resolve, reject) => {
child.addListener('error', (code, signal) => {
console.log('ChildProcess error', code, signal);
reject(code);
});
child.addListener('exit', (code, signal) => {
if (code === 0) {
resolve(code);
} else {
console.log('ChildProcess error', code, signal);
reject(code);
}
});
});
};
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...
}
How would I return false from accessSync when it fails to find a file/dir instead of ENOENT?
unit test
it.only('should be able to read a file stream only if a file exist', function() {
let testfile = testpath+'/imageeee.png';
let ok = FileService.existsAsync(testfile);
ok = ok.then((result) => {
console.log('exists: ', result);
return FileService.createReadStream(testfile);
});
ok = ok.then((result) => {
assert.isNotNull(result.path);
assert.equal(result.path, testfile);
assert.isTrue(result.readable, true);
});
return ok;
});
function
existsAsync(path) {
let ok = fs.accessAsync(path, fs.F_OK);
ok = ok.then(function(error) {
if (error) {
return false;
} else {
return true;
}
});
return ok;
},
error
Error: ENOENT: no such file or directory, access '/home/j/Work/imageeee.png'
Anything that throws an error can be wrapped in a try...catch block to capture the error and proceed from there. If this is the problem function here:
fs.accessAsync(path, fs.F_OK);
Wrap it in a try catch and return false in the error case:
try {
fs.accessAsync(path, fs.F_OK);
// ... other code
return true;
} catch(e) {
// log the error ?
return false;
}
Consider this as an alternative solution to avoid the ENOENT error by using 'child_process' with cat instead of the 'fs' capabilities to know if a file exists or not (with an actual catch error exception working without interfere with your main current process).
const { exec } = require('child_process');
function is_file(path){
return new Promise(resolve => {
try {
exec(`cat ${path}`, (err, stdout, stderr) => { // cat required
if (err) {
resolve(false);
} else {
resolve(true);
}
});
} catch ( e ) { resolve(false); }
});
}
async function main(){
let file = `foo.txt`;
if ( (await is_file(file)) ) {
console.log(`file exists: ${file}`);
} else {
console.log(`no such file: ${file}`);
}
}
main();
the solution is to:
1) Promisify the method that calls accessAsync
2) resolve the error if there is one instead of rejecting it
This will still return the error if the result is false but it will not break the promise chain. In order to return false you can simply do resolve(false) but I found it more useful to actual return the error and handle it in my test.
modified code:
existsAsync(path) {
return new Promise((resolve, reject) => {
return fs.accessAsync(path, fs.F_OK, (err, data) => {
if (err) {
resolve(err);
} else {
resolve(true);
}
});
});
},
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);
});