async/await使用不当导致findById未完成就提前返回对象如何解决
问题原因
- 你代码中
await关键字只能等待Promise对象的执行结果,而你调用Account.findById时传入了回调函数,此时该方法不会返回Promise对象,await等同于等待了undefined,会直接继续执行后续逻辑,才会出现循环执行完毕、accData还没完成赋值的问题。
解决方案1:async/await串行执行(适配原有顺序执行逻辑)
'use strict'; module.exports = function accountWithSingleOrganisation(Account) { Account.accountWithSingleOrganisation = function(accessToken, cb) { accessToken.user(function(err, user) { if (err) return cb(err); let accData = {}; user.role(async (err, role) => { if (err) return cb(err); try { for (let it in role.scopes) { const currentScope = role.scopes[it]; if (currentScope.account == null) break; console.log('1'); // 移除回调,直接等待Promise返回结果 const account = await Account.findById(currentScope.account); console.log('2'); // 此处进行数据赋值 accData = Object.assign(accData, { name: account.name, id: account.id, }); }; console.log(accData); return cb(null, accData); } catch (err) { // 统一捕获异步错误 return cb(err); } }); }); }; };
解决方案2:Promise.all并行查询(性能更优)
不需要按顺序处理scope的场景下推荐使用,查询效率远高于串行循环:
'use strict'; module.exports = function accountWithSingleOrganisation(Account) { Account.accountWithSingleOrganisation = function(accessToken, cb) { accessToken.user(function(err, user) { if (err) return cb(err); user.role(async (err, role) => { if (err) return cb(err); try { // 先过滤掉account为空的scope const validScopes = Object.values(role.scopes).filter(scope => scope.account != null); // 批量生成查询Promise const accountQueries = validScopes.map(scope => Account.findById(scope.account)); // 等待所有查询同时完成 const accounts = await Promise.all(accountQueries); // 完成数据赋值,后续数据会覆盖前面的同字段值,和原有逻辑一致 const accData = accounts.reduce((prev, account) => Object.assign(prev, { name: account.name, id: account.id }), {}); console.log(accData); return cb(null, accData); } catch (err) { return cb(err); } }); }); }; };
补充说明
如果你使用的Account.findById原生不支持Promise调用,可通过Node.js内置的util.promisify手动包装后再使用:
const { promisify } = require('util'); const findAccountById = promisify(Account.findById.bind(Account)); // 后续使用 await findAccountById(scope.account) 即可
内容的提问来源于stack exchange,提问作者Parikshit Rathore
相关产品推荐
相关产品推荐

