Node.js Bluebird Promise问题:进程未等待子任务完成就退出
问题分析与代码重构
嘿,我来帮你搞定这个问题~你遇到的核心问题是**map回调里没有返回Promise**,导致Promise.all根本没等到异步操作完成就结束了。
问题根源
你写的wordsToProcess.map回调里,调用ingredient_get()之后没有把它的Promise链返回出去,所以actions数组里全是undefined。Promise.all遇到非Promise的值会直接把它们当成已resolve的结果,于是立刻进入results.then执行process.exit(0),这时候那些ingredient_get的异步操作还在后台跑,还没走到console.log('(2) step ')这一步,程序就已经退出了。
重构后的代码
var wordsToProcess = ['e301', 'e260']; // array with many words (could be more than 2) var actions = wordsToProcess.map((str) => { console.log('(1) step '); // 关键:这里要return整个Promise链! return ingredient_get(str) .then((ingredient_id) => { console.log('(2) step '); // 现在能正常输出了 return ingredient_id; // 这个返回值会被收集到results的数组里 }); }); var results = Promise.all(actions); results.then(ingredientIds => { // 注意:这里是数组,因为Promise.all返回结果数组 console.log('所有任务完成,结果:', ingredientIds); process.exit(0); // 现在只会在所有异步任务完成后执行 }).catch(err => { // 别忘了处理可能的错误,避免未捕获异常导致程序崩溃 console.error('处理过程出错:', err); process.exit(1); }); function ingredient_get(name) { var q_ingredients = knex('ingredients') .select('id').where('name', name) .then(pick_id); var q_synonyms = knex('synonyms') .select('ingredient_id as id').where('name', name) .then(pick_id); return Promise.all([q_ingredients, q_synonyms]) .then(([id1, id2]) => { return id1 || id2; // only one id would be true here }); } // 假设你有这个pick_id函数(原代码里没贴,这里补个示例) function pick_id(rows) { return rows.length ? rows[0].id : null; }
关键改动说明
- 在
map回调里返回Promise链:这是最核心的修复,让actions数组里每个元素都是一个待完成的Promise,Promise.all才会等待所有异步操作结束。 - 修正
results.then的参数名:Promise.all返回的是所有Promise结果组成的数组,所以用ingredientIds比ingredient_id更准确。 - 添加错误处理:异步操作难免出错,加上
catch可以捕获异常,避免程序意外崩溃,同时返回错误退出码。
这样修改后,process.exit(0)就只会在所有ingredient_get的异步操作都完成、所有(2) step都输出之后才会执行啦~
内容的提问来源于stack exchange,提问作者renathy
相关产品推荐
相关产品推荐

