Make function calls for a synchronous loop

I get an array of strings in the request. Each line contains a command that must be executed in its own shell.

var process = require('child_process'); function execCommand(req,res,callback){ var params = req.params.list //list is an array in the request var result = ''; var command = ''; for (var i = 0; i < params.length; i++) { command = params[i]; cmd = process.exec(command); cmd.stdout.on('data', function(data){ //push the shell output in variable result }); cmd.on('close', function(code) { //convert the variable result to a valid JSON }); } res.send(result); }; 

The result of all commands is confused in the variable result . How to make function calls in a for loop synchronous?

+8
javascript
source share
4 answers

You can use execSync or ...

You need to add a control flow library to help with asynchronous calls, so you can run your functions in series or in parallel:

+2
source share

Use execSync instead of exec!

  for (var i = 0; i < params.length; i++) { command = params[i]; result += process.execSync(command).toString(); } 

As others have noted, this might not be a good idea, as it blocks the event loop and any queries made. This is acceptable if the running processes take a very short amount of time, but not otherwise.

Here is a simple template for controlling the flow of asynchronous functions in a for loop ... every time the process returns, params_finished incremented by one. As soon as the number of ready processes is equal to the total number of processes sent by the response.

  for (var i = 0, total_params=params.length, params_finished=0; i < total_params; i++) { command = params[i]; cmd = process.exec(command); cmd.stdout.on('data', function(data){ //push the shell output in variable result }); cmd.on('close', function(code) { //convert the variable result to a valid JSON params_finished++ if(params_finished == total_params){ res.send(result); } }); } 
+5
source share

An alternative would be to use the equivalent of the sleep function inside a loop. If you know more or less how long it takes for each instance of the loop.

 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function myLoopFunction(){ // any code before loop for (var i = 0; i < params.length; i++) { // do whatever await sleep(3000); // 3000 milisecond, for instance } }; 

See this answer for a full explanation of how this approach works.

0
source share

Use this function in a serial synchronous loop.

 function eachSeries(array, fn) { return new Promise(function (resolveGlobal, rejectGlobal) { var promises = [] var next = 0 fn(array[next], resolveObj, rejectObj) function resolveObj(data) { promises.push( Promise.resolve(data) ) next++ if (next >= array.length) { Promise.all(promises).then(function (data) { resolveGlobal(data) }).catch(function (error) { rejectGlobal(error) }) } else { fn(array[next], resolveObj, rejectObj) } } function rejectObj(error) { return rejectGlobal(error) } }) } 

And you use this function like this ...

 var process = require('child_process'); function execCommand(req,res,callback){ var params = req.params.list //list is an array in the request var result = [] eachSeries(params, function (param, resolve, reject) { cmd = process.exec(param) cmd.stdout.on('data', function (data){ //... after long time you get data, then result.push(data.toObject()) resolve() }) cmd.on("error", function (error){ reject(error) //If something bad happend }) }) .then(function () { console.log("All process executed one by one and pushed...") res.send(result) }) .catch(function (error) { console.log("SOmething broke", error) res.send(error) }) } 

or if you prefer

 var process = require('child_process'); function execCommand(req,res,callback){ var params = req.params.list //list is an array in the request eachSeries(params, function (param, resolve, reject) { cmd = process.exec(param) cmd.stdout.on('data', function (data){ //... after long time you get data, then resolve(data.toObject()) }) cmd.on("error", function (error){ reject(error) //If something bad happend }) }) .then(function (alldata) { res.send(alldata) }) .catch(function (error) { res.send(error) }) } 
0
source share

All Articles