【问题标题】:Saving data from spawned process into variables in Javascript将生成的进程中的数据保存到 Javascript 中的变量中
【发布时间】:2021-01-07 17:42:38
【问题描述】:

我在保存生成的 python 进程的结果时遇到问题。将数据转换为 json 后,我在调用 spawn 过程之前将数据推送到函数中定义的数组,但数组一直返回未定义。我可以 console.log 并正确显示数据,但是从函数返回的数组是未定义的。任何投入将不胜感激。提前致谢。

function sonar_projects(){
    const projects = [];
    let obj;
    let str = '';
    const projects_py = spawn('python', ['sonar.py', 'projects']);
    let test = projects_py.stdout.on('data', function(data){
        let projects = [];
        let json = Buffer.from(data).toString()
        str += json
        let json2 = json.replace(/'/g, '"')
        obj = JSON.parse(json2)
        console.log(json2)
        for(var dat in obj){
            var project = new all_sonar_projects(obj[dat].key, obj[dat].name, obj[dat].qualifier, obj[dat].visibility, obj[dat].lastAnalysisDate);
            projects.push(project); 
        }   
        for (var i= 0; i < projects.length; i++){
             console.log(projects[i].key + ' ' + projects[i].name + '  ' + projects[i].qualifier + '  ' + projects[i].visibility + '  ' + projects[i].lastAnalysisDate)
        }
        console.log(projects)
        return projects;
    });  
}

【问题讨论】:

    标签: javascript child-process spawn


    【解决方案1】:

    首先,通过 NodeJS 文档,我们有

    1. Child Process
    2. [child_process.spawn(command, args][, options])
    3. Child Process Class
    4. Stream
    5. Stream Readable Event "data"

    即使projects_py.stdout.on(event_name, callback) 接受回调,它也会返回类似EventEmitter 的对象,其中注册了事件(在这种情况下,stdout 调用了它的方法on)或@987654330 @ 元素(ChildProcess 名为 projects_py)。

    这是因为每次"data"事件发生时都会调用callback函数。因此,如果事件的分配返回与callback 函数相同,它只会返回一次,然后"data" 事件的下一次发生将由该函数处理,但不会完成.

    在这种情况下,我们需要一种方法来收集和编译projects_py.stdout.on("data", callback)事件完成后的数据。 你已经有了收集部分。现在看看另一个:

    就在您创建 on "data" 事件之前,我们创建了一个封装该过程的承诺:

        // A promise says "we promise" to have something in the future,
        //  but it can end not happening
        var promise = new Promise((resolve, reject) => {
            // First of all, we collect only the string data
            //  as things can come in parts
            projects_py.stdout.on('data', function(data){
                let json = Buffer.from(data).toString()
                str += json
            });
            
            // When the stream data is all read,
            //  we say we get what "we promised", and give it to "be resolved"
            projects_py.stdout.on("end", () => resolve(str));
            
            // When something bad occurs,
            //  we say what went wrong
            projects_py.stdout.on("error", e => reject(e));
            
        // With every data collected,
        //  we parse it (it's most your code now)
        }).then(str => {
            let json2 = str.replace(/'/g, '"')
            // I changed obj to arr 'cause it seems to be an array
            let arr = JSON.parse(json2)
            //console.log(json2)
            
            const projects = []
            // With for-of, it's easier to get elements of
            //  an object / an array / any iterable
            for(var dat of arr){
                var project = new all_sonar_projects(
                    dat.key, dat.name, dat.qualifier,
                    dat.visibility, dat.lastAnalysisDate
                );
                projects.push(project); 
            }
            
            // Template strings `a${variable or expression}-/b`
            //  are easier to compile things into a big string, yet still fast
            for(var i = 0; i < projects.length; i++)
                console.log(
                    `${projects[i].key} ${projects[i].name} ` +
                    `${projects[i].qualifier}  ${projects[i].visibility} ` +
                    projects[i].lastAnalysisDate
                )
            console.log(projects)
            
            // Your projects array, now full of data
            return projects;
        // Finally, we catch any error that might have happened,
        //  and show it on the console
        }).catch(e => console.error(e));
    }
    

    现在,如果您想对您的一系列项目做任何事情,有两个主要选择:

    承诺(then/catch)方式

    // Your function
    function sonar_projects(){
        // The new promise
        var promise = ...
        
        // As the working to get the projects array
        //  is already all set up, you just use it, but in an inner scope
        promise.then(projects => {
            ...
        });
    }
    

    此外,您可以只返回 promise 变量并使用它在 sonar_projects 之外执行承诺(使用 then / catch 和回调)。

    异步 / 等待方式

    // First of all, you need to convert your function into an async one:
    async function sonar_projects(){
        // As before, we get the promise
        var promise = ...
        
        // We tell the function to 'wait' for it's data
        var projects = await promise;
        
        // Do whatever you would do with the projects array
        ...
    }
    

    【讨论】:

    • 非常感谢。这个问题困扰了我一上午!我是 javascript 新手,非常感谢您提供的信息!
    • @CS146R 实际上,我是在您发布问题后 4 分钟开始写这篇文章的,但我花了将近一个小时才写完。我很高兴我在 Stack Overflow 上的第一个答案有点用处。
    猜你喜欢
    • 1970-01-01
    • 2012-12-31
    • 2020-03-22
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2013-11-10
    • 2021-10-04
    相关资源
    最近更新 更多