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

含Promise的async函数重构疑问:是否必须保留new Promise?

问题根源与修复方案

核心问题是:你修改后的doSomething函数没有返回一个能追踪异步操作完成状态的Promise,导致await后拿到undefined。

为什么会这样?

原代码里的new Promise是用来把Room.aggregatePaginate这个回调式异步API转换成Promise风格的——因为这个API不会返回Promise,只能通过传入回调函数获取结果。当你把new Promise去掉后:

  1. doSomething作为async函数,执行到Room.aggregatePaginate(...)这一行就会继续往下走,直接结束函数,默认返回undefined(因为你没写return语句)。
  2. 回调函数里的return {...}只是回调自己的返回值,和外层的doSomething函数的返回值完全没关系,外层函数根本拿不到这个结果。

正确的修改方式

你需要保留对回调API的Promise包装,但可以优化写法(原代码里new Promise的executor用async是多余的,还会导致错误无法被reject捕获),正确的写法如下:

async function doSomething(userId) {
  const query = 'my-query';
  const roomAggregate = Room.aggregate(query).allowDiskUse(true);

  // 把回调式API包装成Promise,这一步是必须的
  const data = await new Promise((resolve, reject) => {
    Room.aggregatePaginate(roomAggregate, (err, data) => {
      if (err || !data) {
        reject(err); // 用reject传递错误,而不是throw
      } else {
        resolve(data);
      }
    });
  });

  // 处理数据逻辑
  const rooms = [];
  for (let room of data.docs) {
    const roomId = room._id;
    room = await computeAThing(room, {
      loadWriteUps: false,
      loadCreators: false,
    });
    room.userCompleted = await computeBThing(userId, roomId);
    rooms.push(room);
  }

  // 直接返回结果,async函数会自动把它包装成Promise
  return {
    rooms,
    success: true,
    paginator: {
      // 分页相关数据
    },
  };
}

额外说明

  1. 原代码里的new Promise(async (resolve, reject) => { ... })是错误的写法:executor函数用async的话,里面的throw不会被Promise的reject捕获,应该直接用普通函数,遇到错误调用reject(err)。
  2. async函数的作用是让你可以用await语法,但它不能自动把回调式API转换成Promise——对于这类老的回调API,你还是需要手动用new Promise包装,或者用工具函数(比如util.promisify)。

内容的提问来源于stack exchange,提问作者Leo Messi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 22:00:23