Node.js调用Python子进程返回值未正确获取的解决请求
问题:Node.js调用Python子进程时无法正确获取返回值导致渲染数据undefined
相关代码
getPred.js
const {spawn} = require('child_process'); const path = require('path'); const getPred = () => { return new Promise((resolve, reject) => { var myjson = {} const pythonProcess = spawn('python3', [ "-u", path.join( __dirname ,'..', '..', 'scripts', 'run.py'), 'file' ]); pythonProcess.stdout.on('data', (data) => { mystr = data.toString(); myjson = JSON.parse(mystr); console.log(myjson.predict); }); pythonProcess.stderr.on('data', (data) => { console.log("fails") console.log(`error:${data}`); }); pythonProcess.on('close', () => { console.log("Closed"); }); resolve(myjson); }); } module.exports = {getPred};
main.js
router.post('/predict', async function (req, res, next) { const myjson = await getPred.getPred(); console.log(myjson); console.log("Final", myjson.predict); res.render('print.ejs', { prods: myjson.predict, pageTitle: 'MegNav', path: '/', hasProducts: 1, activeShop: true, productCSS: true, onPredict: 1 }); });
输出结果
Final undefined 1 Closed
问题描述
getPred()函数调用Python脚本获取预测值,但main.js中console.log(myjson)在Python子进程关闭前执行,导致myjson值为undefined。移除async、await和Promise也无法得到正确结果,需要解决该问题,使myjson先获取值再执行页面渲染。
解决方案
问题核心是Promise的resolve时机错误——代码在创建Promise后立刻调用了resolve(myjson),此时Python子进程还没输出数据,myjson还是初始空对象。必须等到子进程执行完成、所有输出数据收集并解析后再resolve,同时完善错误处理逻辑。
修改后的getPred.js
const { spawn } = require('child_process'); const path = require('path'); const getPred = () => { return new Promise((resolve, reject) => { let stdoutData = ''; const pythonProcess = spawn('python3', [ "-u", path.join(__dirname, '..', '..', 'scripts', 'run.py'), 'file' ]); // 分段收集Python输出内容 pythonProcess.stdout.on('data', (data) => { stdoutData += data.toString(); }); // 捕获Python脚本的错误输出 pythonProcess.stderr.on('data', (data) => { console.error(`Python脚本错误: ${data}`); reject(new Error(`Python脚本执行失败: ${data}`)); }); // 子进程执行完成后解析数据并返回 pythonProcess.on('close', (code) => { console.log("Closed"); if (code === 0) { try { const myjson = JSON.parse(stdoutData); console.log(myjson.predict); resolve(myjson); } catch (parseErr) { console.error('JSON解析失败:', parseErr); reject(parseErr); } } else { reject(new Error(`Python脚本异常退出,退出码: ${code}`)); } }); // 处理子进程启动失败的情况 pythonProcess.on('error', (err) => { console.error('无法启动Python子进程:', err); reject(err); }); }); } module.exports = { getPred };
配套main.js优化(添加错误捕获)
router.post('/predict', async function (req, res, next) { try { const myjson = await getPred.getPred(); console.log("Final", myjson.predict); res.render('print.ejs', { prods: myjson.predict, pageTitle: 'MegNav', path: '/', hasProducts: 1, activeShop: true, productCSS: true, onPredict: 1 }); } catch (err) { console.error('获取预测值失败:', err); // 返回错误响应,避免请求挂起 res.status(500).send('获取预测数据失败,请稍后重试'); } });
修改要点说明
- 新增
stdoutData变量:Python脚本可能分多次输出数据,拼接后再解析能避免JSON解析失败 - 调整resolve时机:将
resolve移到子进程close事件回调中,确保子进程执行完毕、数据完整后再返回结果 - 完善错误处理:覆盖子进程启动失败、脚本错误退出、JSON解析失败等场景,通过
reject传递错误,便于上层捕获处理 - main.js添加try-catch:防止因Python脚本出错导致请求长时间挂起,给用户明确的错误反馈
内容的提问来源于stack exchange,提问作者NavinKumarmMNK
相关产品推荐
相关产品推荐

