如何打开Child_process.spawn的"Promise"语法“异步/等待";句法 [英] how to turn Child_process.spawn's "Promise" syntax to "async/await" syntax

查看:117
本文介绍了如何打开Child_process.spawn的"Promise"语法“异步/等待";句法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有这段代码,我试图全面了解async/await语法.以下是该代码的 Promise 版本:

So I have this code and I'm trying to understand the async/await syntax in full depth. The below is the Promise version of the code:

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".

I have some python code I want to execute in tools/__main__.py so that's why I'm calling "pipenv".

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

Here's my attempt to do write it in async/await way (which actually works):

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
    }
}

但是我所做的只是从某人的示例中复制并粘贴,其中我有等待... 循环.

But all I did was copy and paste from someone's example where I have for await... loop.

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

Therefore I've been trying to rewrite this same code so that I can actually understand it but I've been failing for days now.

还有其他方法可以使用 async/await 方式编写此代码,而无需使用 for await ... 循环吗?

Are there any other ways to write this code with async/await way without using the for await... loop?

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

Also I have no idea how I can access data except for using the .then syntax:

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

我还如何从 resolve(data)访问数据"?

How else would I access "data" from resolve(data)?

非常感谢.

推荐答案

使用 async/await 编写代码的方法可能不是更好的>适用于Node中的异步(流块)语法.节点流专门实现了一个异步迭代器以允许这样做.

There are probably not better ways to write the code using async/await than using the for async (chunk of stream) syntax in Node. Node streams implement an asynchronous iterator specifically to allow doing so.

关于2ality的文章具有更深入的解释和讨论.关于 Symbol.asyncIterator 的MDN文章 for-await ... of更广泛地介绍异步迭代.

This article on 2ality has more in-depth explanation and discussion. MDN articles on Symbol.asyncIterator and for-await...of cover asynchronous iteration more generally.

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

Once using asychronous iteration has been decided it must be used in an async function, which will return a promise.

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

While using a then clause on the returned promise is a completely normal way of getting the data, you could also await the result of callToolsAsync(req) - provided of course that the call is coded inside an async function so that await is in a valid context.


以下代码 experiment 获得了 stdio stderr 的输出,以及子进程的退出代码.它不使用Python或解析数据.


The following code experiment gets the stdio and stderr output, and the exit code from a child process. It doesn't use Python or parse data.

main.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);
}

这表明

  • 控制台警告节点中可读流的异步迭代仍处于试验阶段,
  • 用于等待(流块)的循环循环似乎一直循环到关闭流为止-在这种情况下,这意味着 await 将在不打开的流上等待"当时没有可用数据.
  • 从其管道中检索 stdout stderr 内容,并且由于检索是异步的,因此可以不按特定顺序获取退出代码.
  • 合并从另一个进程通过管道到达的大块数据不是可选的-子进程的控制台日志是单独传递的.
  • A console warning that async iteration of a readable stream is still experimental in node,
  • The for await (chunk of stream) loops seem to loop until the stream is closed - in this case meaning that await will wait on an open stream that doesn't have data available at the time.
  • retrieving stdout and stderr content from their pipes, and getting the exit code can be done in no particular order since retrieval is asynchronous.
  • Amalgamating chunks of data arriving through pipes from another process is not optional - console logs from the child process came through separately.

这篇关于如何打开Child_process.spawn的"Promise"语法“异步/等待";句法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆