使用async.waterfall时模型返回undefined问题排查与修复
问题原因分析
你的代码里出现undefined的核心原因有两个:
- Async.js的
waterfall是回调式API,不返回Promise:你用await去等待它完全无效,因为它本身不会返回一个Promise对象,所以let waterfall = await Async.waterfall(...)自然会得到undefined。 - 回调函数的返回值无法被外层函数捕获:最后那个
function(err, result)里的return {'data': tmp};只是回调函数自己的返回值,和外层的Profile函数没有任何关系——异步回调执行的时候,Profile函数早就执行完并返回了,根本拿不到这个值。
修复方案
我给你两种修复方式,第二种更推荐,因为代码更简洁易读:
方案一:把waterfall包装成Promise
既然你想用async/await,就得把回调式的waterfall转换成Promise形式,这样await才能生效:
module.exports = async function Profile() { // 用Promise包裹waterfall,手动控制resolve/reject const finalResult = await new Promise((resolve, reject) => { Async.waterfall([ function(callback) { db.getOneWhere('users', 'username', global.req.params.username, ["username"]) .then(result => callback(null, result)) .catch(err => callback(err)); // 别忘了捕获db操作的错误 }, function(arg1, callback) { db.getOneWhere('users', 'username', 'admin', ["username"]) .then(result2 => { const ok = { arg1, result2 }; callback(null, ok); }) .catch(err => callback(err)); } ], function (err, result) { if (err) { reject(err); // 错误时向外抛出 return; } let tmp = []; Object.keys(result).forEach(k => { tmp = [...tmp, ...result[k]]; }); resolve({ 'data': tmp }); // 成功时返回结果 }); }); return finalResult; }
方案二:用纯async/await替代waterfall(更推荐)
既然你的db.getOneWhere已经返回Promise了,完全没必要用Async.waterfall,直接用await按顺序执行异步操作即可,代码更清晰:
module.exports = async function Profile() { try { // 第一步:获取目标用户数据 const userData = await db.getOneWhere('users', 'username', global.req.params.username, ["username"]); // 第二步:获取admin用户数据 const adminData = await db.getOneWhere('users', 'username', 'admin', ["username"]); // 合并两个结果数组 const mergedData = [...userData, ...adminData]; // 返回最终格式 return { 'data': mergedData }; } catch (err) { // 捕获并抛出错误,让上层控制器处理 throw err; } }
验证修复
修改完模型代码后,你的控制器代码Profile().then(response => { console.log(response); });就能正确打印出合并后的data对象了,不会再是undefined。
内容的提问来源于stack exchange,提问作者P. Nick
相关产品推荐
相关产品推荐

