所以我有一个服务器监听 RabbitMQ 请求:
console.log(' [*] Waiting for messages in %s. To exit press CTRL+C', q);
channel.consume(q, async function reply(msg) {
const mongodbUserId = msg.content.toString();
console.log(' [x] Received %s', mongodbUserId);
await exec('./new_user_run_athena.sh ' + mongodbUserId, function(
error,
stdout,
stderr
) {
console.log('Running Athena...');
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
console.log(
' Finished running Athena for mongodbUserId=%s',
mongodbUserId
);
channel.sendToQueue(
msg.properties.replyTo,
new Buffer(mongodbUserId),
{ correlationId: msg.properties.correlationId }
);
channel.ack(msg);
});
问题是执行 shell 脚本
new_user_run_athena.sh
时的等待调用发生在我打印出 Finished running Athena for mongodbUserId
之后。您可以在控制台日志中看到它发生:
[*] Waiting for messages in run_athena_for_new_user_queue. To exit press CTRL+C
[x] Received 5aa96f36ed4f68154f3f2143
Finished running Athena for mongodbUserId=5aa96f36ed4f68154f3f2143
Running Athena...
stdout:
stderr:
是否可以使用异步等待语法来执行 shell 脚本?
由于
exec
看起来需要回调,因此您可以使用它将其包装到承诺中。然后您可以等待该承诺,而不是直接等待 exec
调用。因此,对于您的示例,类似于:
// Await a new promise:
await new Promise((resolve, reject) => {
exec('./new_user_run_athena.sh ' + mongodbUserId, function(
error,
stdout,
stderr
) {
console.log('Running Athena...');
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
// Reject if there is an error:
return reject(error);
}
// Otherwise resolve the promise:
resolve();
});
});
请参阅 MDN 文档了解
await
:
await 运算符用于等待 Promise。它只能在异步函数中使用。
exec
函数不会返回 Promise,因此您不能等待它。
您可以编写一个函数 将
exec
包装在 Promise 中并返回该 Promise。
将 exec 包裹在一个承诺中。这是一个打字稿示例:
import { exec as childProcessExec } from 'child_process'
const exec = async (command: string): Promise<string> => {
return new Promise((resolve, reject) => {
childProcessExec(command, (error, stdout, stderr) => {
if (error !== null) reject(error)
if (stderr !== '') reject(stderr)
else resolve(stdout)
})
})
}
用途:
const commandOutput = await exec('echo Hey there!')
console.log(commandOutput)
根据其他示例,我想出了一个返回对象的类型化异步执行调用:
/**
* Adds typed await and async support
* @param command string
* @returns Promise<{error:ExecException, standardError:string, standardOut:string}
*/
async callProcess(command:string): Promise<{error:ExecException, standardError:string, standardOut:string}> {
return new Promise((resolve, reject) => {
childProcessExec(command, (error: ExecException, standardOut: string, standardError: string) => {
var result = {error, standardError, standardOut};
if (error !== null) {
reject(result);
}
if (standardError !== '') {
reject(result);
}
else {
resolve(result);
}
})
})
}
你这样称呼它:
try {
var callResult = await this.callProcess(execCommand);
if (callResult.standardOut) {
}
}
catch(error) {
if (error.standardError) {
}
else if (error.error) {
}
else {
}
}
返回字符串的示例:
/**
* Adds typed await and async support.
* In a try block returns standard out and error in catch block.
* @param command string
* @returns Promise<string>
*/
async callProcess(command:string): Promise<string> {
return new Promise((resolve, reject) => {
childProcessExec(command, (error: ExecException, standardOut: string, standardError: string) => {
if (error !== null) {
reject(error);
}
if (standardError !== '') {
reject(standardError);
}
else {
resolve(standardOut);
}
})
})
}
尚未经过全面测试,因此请添加任何更正。