NODEjs在for循环中同步exec语句
NODEjs synchronizing exec statements inside for loop
我想创建一个程序,在其中我从目录中读取文件,然后在其他目录中 grep 这些名称。
代码如下:
var exec = require('child_process').exec;
var internalCount = 0;
var i = -1;
for (; i < fileNamesInDir.length / 2;) {
if (i === internalCount) {
continue;
}
(function () {
i = internalCount;
var j = i;
exec('grep -nre js/' + fileNamesInDir[j] +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt',
function (error, stdout, stderr) {
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += "RESULTS FOR ::" + fileNamesInDir[j];
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += stdout;
outputString += "\n";
if (++internalCount === fileNamesInDir.length) {
writeToFile();
}
});
})();
}
问题是执行语句不同步,回调函数 return 数据异步。为了解决这个问题,我采用了另一个变量并在迭代索引与该变量相同的情况下继续 for 循环。但是,使用此代码,它会进入无限循环,并且不会触发任何 exec 语句。
A for
在 Javascript 运行 中同步循环,这里无法告诉它等待循环中的任何内容。如果您尝试各种 hack,由于 Javascript 的单线程特性,您最终会 运行 陷入障碍或无限循环。所以......基本上你不能让 for
循环等待循环内的异步操作完成,然后再进入循环的下一次迭代。所以,你必须用不同的方式解决你的问题。
这是一个异步迭代的通用方案,其中操作协调并一个接一个地完成:
var i = 0;
var outputString = "";
function next() {
if (i < fileNamesInDir.length) {
exec('grep -nre js/' + fileNamesInDir[i] +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt',
function (error, stdout, stderr) {
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += "RESULTS FOR ::" + fileNamesInDir[i];
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += stdout;
outputString += "\n";
i++;
next();
});
} else {
writeToFile();
}
}
next();
这将 运行 连续执行每个 grep 操作,以便按顺序连接结果。
但是,您不必 运行 连续执行此类代码。只要您按如下顺序收集结果,就可以运行并行执行所有这些操作:
var exec = require('child_process').exec;
var results = [];
var doneCntr = 0;
fileNamesInDir.forEach(function(item, index) {
exec('grep -nre js/' + item +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt',
function (error, stdout, stderr) {
var outputString = "";
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += "RESULTS FOR ::" + item;
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += stdout;
outputString += "\n";
results[index] = outputString;
++doneCntr;
if (doneCntr === fileNamesInDir.length) {
writeToFile(results.join(""));
}
});
});
}
您的代码还缺少需要添加的错误处理。
我最喜欢的方式是承诺并让 Promise.all()
为我们完成收集结果的工作:
function execP(cmd) {
return new Promise(function(resolve, reject) {
exec(cmd, function(err, stdout, stderr) {
if (err) {
reject(err);
} else {
resolve({stdout, stderr});
}
});
});
}
Promise.all(fileNamesInDir.map(function(item) {
return execP('grep -nre js/' + item +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt').then(function(data) {
return "\n" +
"***********************************************************\n" +
"RESULTS FOR ::" + item + "\n" +
"***********************************************************\n" +
data.stdout + "\n";
});
})).then(function(results) {
var output = results.join("");
// process output here
}, function(err) {
// process error here
});
我想创建一个程序,在其中我从目录中读取文件,然后在其他目录中 grep 这些名称。
代码如下:
var exec = require('child_process').exec;
var internalCount = 0;
var i = -1;
for (; i < fileNamesInDir.length / 2;) {
if (i === internalCount) {
continue;
}
(function () {
i = internalCount;
var j = i;
exec('grep -nre js/' + fileNamesInDir[j] +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt',
function (error, stdout, stderr) {
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += "RESULTS FOR ::" + fileNamesInDir[j];
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += stdout;
outputString += "\n";
if (++internalCount === fileNamesInDir.length) {
writeToFile();
}
});
})();
}
问题是执行语句不同步,回调函数 return 数据异步。为了解决这个问题,我采用了另一个变量并在迭代索引与该变量相同的情况下继续 for 循环。但是,使用此代码,它会进入无限循环,并且不会触发任何 exec 语句。
A for
在 Javascript 运行 中同步循环,这里无法告诉它等待循环中的任何内容。如果您尝试各种 hack,由于 Javascript 的单线程特性,您最终会 运行 陷入障碍或无限循环。所以......基本上你不能让 for
循环等待循环内的异步操作完成,然后再进入循环的下一次迭代。所以,你必须用不同的方式解决你的问题。
这是一个异步迭代的通用方案,其中操作协调并一个接一个地完成:
var i = 0;
var outputString = "";
function next() {
if (i < fileNamesInDir.length) {
exec('grep -nre js/' + fileNamesInDir[i] +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt',
function (error, stdout, stderr) {
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += "RESULTS FOR ::" + fileNamesInDir[i];
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += stdout;
outputString += "\n";
i++;
next();
});
} else {
writeToFile();
}
}
next();
这将 运行 连续执行每个 grep 操作,以便按顺序连接结果。
但是,您不必 运行 连续执行此类代码。只要您按如下顺序收集结果,就可以运行并行执行所有这些操作:
var exec = require('child_process').exec;
var results = [];
var doneCntr = 0;
fileNamesInDir.forEach(function(item, index) {
exec('grep -nre js/' + item +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt',
function (error, stdout, stderr) {
var outputString = "";
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += "RESULTS FOR ::" + item;
outputString += "\n";
outputString +=
"***********************************************************";
outputString += "\n";
outputString += stdout;
outputString += "\n";
results[index] = outputString;
++doneCntr;
if (doneCntr === fileNamesInDir.length) {
writeToFile(results.join(""));
}
});
});
}
您的代码还缺少需要添加的错误处理。
我最喜欢的方式是承诺并让 Promise.all()
为我们完成收集结果的工作:
function execP(cmd) {
return new Promise(function(resolve, reject) {
exec(cmd, function(err, stdout, stderr) {
if (err) {
reject(err);
} else {
resolve({stdout, stderr});
}
});
});
}
Promise.all(fileNamesInDir.map(function(item) {
return execP('grep -nre js/' + item +
' ./ --exclude-dir=node_modules --exclude=searchResults.txt').then(function(data) {
return "\n" +
"***********************************************************\n" +
"RESULTS FOR ::" + item + "\n" +
"***********************************************************\n" +
data.stdout + "\n";
});
})).then(function(results) {
var output = results.join("");
// process output here
}, function(err) {
// process error here
});