如何正确在异步函数的 try-catch 中使用 return 语句

异步函数始终返回 promise,直接 `console.log(createquiz(...))` 只会输出 `promise { pending }`;必须用 `.then()` 或 `await` 获取实际返回值。

在 JavaScript 中,async 函数的本质是语法糖——它自动将返回值包装为 Promise。无论你在 try 或 catch 块中 return "success" 还是 return e.message,该返回值都会被隐式包裹进一个已解决(fulfilled)或已拒绝(rejected)的 Promise 中,而非同步返回原始字符串

因此,以下调用方式是错误的:

console.log(createQuiz(questions, quizDetails)); // ❌ 输出: Promise { pending }

因为 createQuiz() 返回的是一个 Promise 对象,而 console.log 并不会等待它完成。

✅ 正确做法有两种:

方式一:使用 .then() 链式处理(推荐用于顶层调用非 async 环境)

createQuiz(questions, quizDetails)
  .then(result => console.log(result)) // ✅ 输出: "success" 或错误消息
  .catch(err => console.error("Unexpected rejection:", err));

方式二:在 async 上下文中使用 await(更简洁、可读性更强)

async function run() {
  try {
    const result = await createQuiz(questions, quizDetails);
    console.log(result); // ✅ 正确获取返回值
  } catch (err) {
    // 注意:此处仅捕获 createQuiz 内部未处理的异常
    // 但根据当前实现,所有错误都已被 catch 并 return 为字符串,因此此处通常不会进入
    console.error(err);
  }
}
run();

⚠️ 重要注意事项:

  • return 在 async 函数中 不是终止执行,而是决定 Promise 的 fulfill 值;
  • 若 Quiz.create() 抛出错误且被 catch 捕获,return e.message 会生成一个 fulfilled Promise(值为字符串),而非 rejected Promise。这意味着调用方无法用 .catch() 捕获业务错误——除非你显式 throw:
    catch (e) {
      console.error("DB creation failed:", e);
      throw new Error(`Create failed: ${e.message}`); // ✅ 触发 rejected Promise
    }
  • 若希望保持错误语义(即失败时返回 rejected Promise),应避免在 catch 中 return 错误信息,而选择 throw;若需返回结构化结果(如 { success: true, data } 或 { success: false, error }),则应在 try 中统一 return 对象,并由调用方解析。

总结:async/await + try/catch 中的 return 是安全且推荐的,但务必理解其返回的是 Promise;要获取最终值,必须通过 await 或 .then() 解包——这是异步编程的基本契约,而非 bug。