如何 return 来自函数中子进程的值?

How to return value from a child process in a function?

我在 javascript 中生成了一个 python 子进程(用于使用 Microsoft Botframework 编写机器人代码),如下所示:

async function searchForRelevantDoc (context) {
    var msg = context.activity.text;
    var spawn = require('child_process').spawn,
        py    = spawn('python', ['../path/to/file.py', msg]),
        output = '';
    py.stdin.setEncoding = 'utf-8';
    py.stdout.on('data',
    (data) => {
        output += data.toString();
        console.log('output was generated: ' + output);
    });
    // Handle error output
    py.stderr.on('data', (data) => {
    // As said before, convert the Uint8Array to a readable string.
        console.log('error:' + data);
    });
    py.stdout.on('end', async function(code){
        console.log('output: ' + output);
        console.log(`Exit code is: ${code}`);
        // "return" is probably wrong, what should be done instead?
        return output;
        }
    });
}

我希望 output 被 return 编辑为函数 searchForRelevanceDoc() 的值。如何才能做到这一点?我无法使用 await context.sendActivity(output) 而不是 return 语句。错误信息:

TypeError: Cannot perform 'get' on a proxy that has been revoked

函数 searchForRelevanceDoc 的调用方式如下:

//in bot.js
const pysearch = require('../bboti/python-search');

class MyBot {

    // constructor...

    async onTurn(context) {
        // ...
        var search_engine_answer = pysearch.searchForRelevantDoc(context);
        context.sendActivity(search_engine_answer)
        // ...
    }
}

制作你的函数 return new Promise((resovle, reject) => ...) 并解决所需的价值

@Marcos Casagrande 的回答更漂亮,我只是想添加 promise 解决方案。

您可以 return 一个 new Promise 并将 stdout.on 包装在 promise 中。

async function searchForRelevantDoc (context) {
...
    return new Promise((res, rej) => {
        py.stdout.on('end', async function(code){
            console.log('output: ' + output);
            console.log(`Exit code is: ${code}`);
            // "return" is probably wrong, what should be done instead?
            res(output);
        })
    });
}

Promises hot-load 因此无论何时您声明一个 promise 函数都会开始 运行。所以基本上活动都会附上。

searchForRelevantDoc 到 return/resolve output 的最简单方法,使用 async/await 是使用在 Node 11.13.0 中添加的 events.once,并且等待 py

close 事件
const { once } = require('events'); // Added in Node 11.13.0

async function searchForRelevantDoc (context) {
    var msg = context.activity.text;
    var spawn = require('child_process').spawn,
        py    = spawn('python', ['../path/to/file.py', msg]),
        output = '';

    py.stdin.setEncoding = 'utf-8';

    py.stdout.on('data', (data) => {
        output += data.toString();
        console.log('output was generated: ' + output);
    });
    // Handle error output
    py.stderr.on('data', (data) => {
    // As said before, convert the Uint8Array to a readable string.
        console.log('error:' + data);
    });
    py.stdout.on('end', async function(code){
        console.log('output: ' + output);
        console.log(`Exit code is: ${code}`);
    });

    await once(py, 'close')

    return output;
}

如果您使用的是旧版本的 Node,您可以将其包装在 new Promise


async function searchForRelevantDoc (context) {
    // ...

    // You can also check for `code` and reject if a non zero code is returned
    await new Promise(resolve => py.on('close', resolve));

    return output;
}

然后在调用searchForRelevantDoc时需要使用await.then

class MyBot {

    // constructor...

    async onTurn(context) {
        // ...
        var search_engine_answer = await pysearch.searchForRelevantDoc(context);
        context.sendActivity(search_engine_answer)
        // ...
    }
}