运行 几个 exec() 命令一个接一个

Run few exec() commands one-by-one

我需要 运行 两个 shell 命令,一个接一个。这些命令包含在函数中:

function myFucn1() {
     exec('some command',
        (error, stdout, stderr) => {
            if (error) {
                console.error(`exec error: ${error}`);
                throw error;
            }
            console.log(`stdout: ${stdout}`);
            console.error(`stderr: ${stderr}`);
        });
}

function myFucn2() {
     exec('some command 2',
        (error, stdout, stderr) => {
            if (error) {
                console.error(`exec error: ${error}`);
                throw error;
            }
            console.log(`stdout: ${stdout}`);
            console.error(`stderr: ${stderr}`);
        });
}

当我在触发函数上调用它们时:

app.get('/my_end_point', (req, res) => {
    try {
        myFucn1();
        myFucn2();
        res.send('Hello World, from express');
    } catch (err) {
        res.send(err);
    }
});

它 运行 两个命令的顺序和输出都是随机的 stdout, stderr 仅从第二个函数显示。

这是由于 Javascript 回调函数的性质。调用 Exec 函数,并在结果可用时调用 { } 中的函数(因此命令可能完成)。函数立即退出,第二个函数甚至在您的命令完成之前执行。

一种可能的解决方案(但不是很好)是将 myFucn2() 的调用放在 myFucn1() 的回调中(例如:在 console.error 之后)。

正确的解决方案是使用单独的线程(参见 'worker threads')来跟踪 myFucn1() 的执行,并在它完成时执行第二个线程。

您可以使用 execSync 而不是 exec 来同步执行您的命令。

const { execSync } = require("child_process");

function myFucn1() {
  return execSync("echo hello").toString();
}
function myFucn2() {
  return execSync("echo world").toString();
}

myFucn1();
myFucn2();

命令每次不按相同顺序执行的原因是因为它们一个接一个地启动,但从那时起 JS 无法控制如何执行他们将被处决。因此,对于像您这样的程序,基本上是这样的:

launch cmd1, then do callback1
launch cmd2, then do callback2
respond to the client

您无法控制 callback1callback2 何时执行。根据你的描述,你面对的是这个:

launch cmd1
launch cmd2
respond to the client
callback2
(something else happens in your program)
callback1

这就是为什么你只看到你所看到的。


所以,让我们试着强制执行他们的执行顺序吧!您可以使用 child_process' execSync 但我不建议将其用于生产,因为它会使您的服务器程序在您的子进程执行的整个过程中保持空闲状态。

但是,通过使用 async/await 并将 exec 转换为异步函数,您可以获得非常相似的语法:

const { exec: execWithCallback } = require('child_process');
const { promisify } = require('util');
const exec = promisify(execWithCallback);

async function myFunc1() {
  try {
    const {stdout, stderr} = await exec('command 1');
  } catch(error) {
    console.error(`exec error: ${error}`);
    throw error;
  }
}

// same for myFunc2

以及您的服务器:

app.get('/my_end_point', async (req, res) => {
  try {
    await myFunc1();
    await myFunc2();
    res.send('Hello World, from express');
  } catch (error) {
    res.send(error);
  }
});