Javascript NodeJS-在数组中的每个元素之间按顺序循环并超时
我有一个数组中需要按顺序运行的命令列表:Javascript NodeJS-在数组中的每个元素之间按顺序循环并超时,javascript,node.js,arrays,loops,timeout,Javascript,Node.js,Arrays,Loops,Timeout,我有一个数组中需要按顺序运行的命令列表: const commands = [ `git clone https://github.com/EliLillyCo/${repo}.git`, `cd ${repo}`, `git checkout -b ${branch}`, 'cp ../codeql-analysis.yml .github/workflows/', 'git add .github/workflows/codeql-analysis.yml', `git
const commands = [
`git clone https://github.com/EliLillyCo/${repo}.git`,
`cd ${repo}`, `git checkout -b ${branch}`,
'cp ../codeql-analysis.yml .github/workflows/',
'git add .github/workflows/codeql-analysis.yml',
`git push --set-upstream origin ${branch}`,
'cd ../',
`rm -r ${repo}`,
];
由于命令依赖于正在运行的前一个命令,因此需要按顺序运行这些命令
此外,在运行下一个命令之前,每个命令需要等待3秒钟,因为有时命令需要时间,尤其是command1和command5
我使用标准的for
循环,然后使用调用函数来运行命令的setTimeout()
,例如:
const a = require('debug')('worker:sucess');
const b = require('debug')('worker:error');
const { exec } = require('child_process');
function execCommand(command) {
exec(command, (error, stdout, stderr) => {
if (error) {
b(`exec error: ${error}`);
return;
}
a(`stdout: ${stdout}`);
b(`stderr: ${stderr}`);
});
}
const commands = [
`git clone https://github.com/EliLillyCo/${repo}.git`,
`cd ${repo}`, `git checkout -b ${branch}`,
'cp ../codeql-analysis.yml .github/workflows/',
'git add .github/workflows/codeql-analysis.yml',
`git push --set-upstream origin ${branch}`,
'cd ../',
`rm -r ${repo}`,
];
for (let i = 0; i < commands.length; i++) {
setTimeout(execCommand(commands[i]), 3000);
}
解决在使用超时时按顺序循环数组的问题的最佳方法是什么?我会让
execCommand
返回一个承诺,以便您知道何时完成;你不能依赖超时(如果任务需要三秒钟以上怎么办?),因为大多数命令的完成速度都比这快得多,超时会不必要地拖延时间
下面是返回承诺的execCommand
:
function execCommand(command) {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
b(`exec error: ${error}`);
reject(error);
return;
}
a(`stdout: ${stdout}`);
b(`stderr: ${stderr}`);
resolve();
});
});
}
然后,如果您有顶级wait
可用(modern Node.js和ESM模块):
如果没有,请将其包装在async
iLife中:
(async () => {
for (const commmand of commands) {
await execCommand(command);
}
})().catch(error => {
// ...report/handle error...
});
或者,如果您想将执行与处理
stdout
/stderr
分开,您可以直接使用onexec
,但将它们结合在一起对您所做的改动最小,这就是我一直坚持的观点。当前,您不能保证在调用下一个命令时上一个命令会完成。3000毫秒后自动调用下一个,但上一个可能需要比预期更长的时间,并且尚未结束
您应该添加一个机制来等待每个命令,然后启动下一个命令。下面介绍如何使用async/await
:
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const commands = [ ... ];
const execCommand = async (command) => {
try {
await exec(command)
} catch (error) {
b(`exec error: ${error}`);
return;
}
a(`stdout: ${stdout}`);
b(`stderr: ${stderr}`);
}
(async () => {
for (let command of commands) {
await execCommand(command);
}
})();
正确的语法是
setTimeout(execCommand,3000)
或setTimeout(()=>{execCommand(commands[i])},3000)
是wait execCommand(commands)代码>的意思是:等待执行命令(command)代码>它仍然没有等待上一个命令完成。在最后一个命令完成之前,这些命令似乎仍在运行?@user3180997-是的,execCommand(commands)
应该是execCommand(command)
,对此表示抱歉。根据,在进程退出之前,exec
不会调用其回调。因此,如果你认为承诺在那之前就已经达成,它暗示了三件事之一:1。您没有完全正确地实现上述内容(抱歉:-),或者2。命令已完成,您看到的有不同的解释,或者。。。。。。3.您正在调用的进程只是启动另一件不会阻止您正在创建的进程终止的事情,并在后台继续其工作。但是上面的execCommand
肯定会等待进程开始退出,至少根据Node.js文档是这样。不用担心,只是想再次检查一下。当我把cd../
作为第一个命令,把pwd
作为第二个命令时,pwd
打印出我当前所在的目录,而不是cd../
应该放我进去的目录。因此,我认为它要么没有运行cd../
要么pwd
首先出现。感谢您的响应。它仍然没有等待上一个命令完成。在最后一个命令完成之前,命令似乎仍然在运行?嗯,我不明白为什么,因为一切都返回一个承诺,并且按顺序等待,我知道,我已经添加了一张cd../
和pwd
,并且pwd在cd出现之前打印出来:/
(async () => {
for (const commmand of commands) {
await execCommand(command);
}
})().catch(error => {
// ...report/handle error...
});
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const commands = [ ... ];
const execCommand = async (command) => {
try {
await exec(command)
} catch (error) {
b(`exec error: ${error}`);
return;
}
a(`stdout: ${stdout}`);
b(`stderr: ${stderr}`);
}
(async () => {
for (let command of commands) {
await execCommand(command);
}
})();