You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 18:24:03