javascript - 如何将 Child_process.spawn 的 "Promise"语法转换为 "async/await"语法

标签 javascript node.js asynchronous child-process

所以我有了这段代码,我正在尝试全面深入地理解 async/await 语法。以下是代码的 Promise 版本:

function callToolsPromise(req) {
    return new Promise((resolve, reject) => {
        let pipshell = 'pipenv';
        let args = ['run', 'tools'];
        req.forEach(arg => {
            args.push(arg)
        });
        tool = spawn(pipshell, args);
        tool.on('exit', (code) => {
            if (code !== 0) {
                tool.stderr.on('data', (data) => {
                    reject(data);
                });
            } else {
                tool.stdout.on ('data', (data) => {
                    resolve(JSON.parse(data)):
                });
            }
        });
    })
}

我有一些要在 tools/__main__.py 中执行的 python 代码,所以这就是我调用“pipenv”的原因。

这是我尝试以 async/await 方式(实际上有效)编写它:

async function callToolsAsync(req) {
    let pipshell = 'pipenv';
    let args = ['run', 'tools'];
    req.forEach(arg => {
        args.push(arg)
    });
    let tool = spawn(pipshell, args);
    for await (const data of tool.stdout) {
        return data
    }
}

但我所做的只是从某人的示例中复制并粘贴我有 for await... 循环的示例。

因此,我一直在尝试重写相同的代码,以便我能够真正理解它,但我已经失败了好几天了。

是否有任何其他方法可以在不使用 for await... 循环的情况下使用 async/await 方式编写此代码?

除了使用 .then 语法外,我也不知道如何访问数据:

callToolsAsync(['GET','mailuser'])
.then(console.log)

我还能如何从 resolve(data) 访问“数据”?

非常感谢。

最佳答案

可能没有比使用 for async (chunk of stream) 语法使用 async/await 编写代码的更好方法了 Node 。 Node 流实现了一个专门用于允许这样做的异步迭代器。

article on 2ality有更深入的解释和讨论。关于 Symbol.asyncIterator 的 MDN 文章和 for-await...of更普遍地涵盖异步迭代。

一旦决定使用异步迭代,就必须在 async 函数中使用它,该函数将返回一个 promise。

虽然在返回的 promise 上使用 then 子句是获取数据的完全正常的方式,但您也可以 await callToolsAsync(req) 的结果 - 当然前提是调用在 async 函数中编码,以便 await 处于有效上下文中。


以下代码 experiment 获取 stdiostderr 输出,以及子进程的退出代码。它不使用 Python 或解析数据。

ma​​in.js(输入node main.js运行)

// main.js
async function spawnChild() {
    const { spawn } = require('child_process');
    const child = spawn('node', ["child.js"]);

    let data = "";
    for await (const chunk of child.stdout) {
        console.log('stdout chunk: '+chunk);
        data += chunk;
    }
    let error = "";
    for await (const chunk of child.stderr) {
        console.error('stderr chunk: '+chunk);
        error += chunk;
    }
    const exitCode = await new Promise( (resolve, reject) => {
        child.on('close', resolve);
    });

    if( exitCode) {
        throw new Error( `subprocess error exit ${exitCode}, ${error}`);
    }
    return data;
}

spawnChild().then(
    data=> {console.log("async result:\n" + data);},
    err=>  {console.error("async error:\n" + err);}
);

child.js

// child.js
console.log( "child.js started"); //  stdout
setTimeout( finish, 1000);
function finish() {
    console.log( "child.js: finish() call");  //  stdout 
    console.error("child exit using code 1"); //  stderr
    process.exit(1);
}

这表明

  • 控制台警告可读流的异步迭代在 Node 中仍处于试验阶段,
  • for await (chunk of stream) 循环似乎一直循环直到流关闭 - 在这种情况下意味着 await 将等待一个打开的流当时没有可用数据。
  • 从它们的管道中检索 stdoutstderr 内容,并获取退出代码可以不按特定顺序完成,因为检索是异步的。
  • 合并通过管道从另一个进程到达的数据 block 是不是可选的 - 来自子进程的控制台日志是单独通过的。

关于javascript - 如何将 Child_process.spawn 的 "Promise"语法转换为 "async/await"语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58570325/

相关文章:

javascript - 多个日期选择器字段 id

javascript - 如何在 JavaScript 中 console.log 阿拉伯文文本?

c# - 如何在 API 中向客户端代码公开实现生产者消费者管道的类?

node.js - 如何在 node-pdfkit 中使用异步函数?

javascript - 如何根据页面位置实现 ng-show

javascript - JSON获取一个值(很菜鸟)

javascript - 异步函数 promise 何时解决?

c# - 在异步方法中显示进度对话框

javascript - 如何从 ember.js 中的 .json 文件中检索模型

node.js - 这是在 mongodb 中插入和更新对象数组的安全方法吗?