async是javascript关键字,用于声明异步函数,需配合await、try-catch、to()工具函数、框架中间件及全局unhandledrejection监听实现健壮错误处理。

async 本身不是“包”,而是一个 JavaScript 关键字,用于声明异步函数。它不能直接“包装”普通函数来自动处理错误——但它配合 await 和结构化错误处理机制(如 try-catch、to() 辅助函数或统一错误中间件),能显著提升异步错误的可控性与可维护性。关键不在于“用 async 包装”,而在于如何设计异步流程并嵌入健壮的错误捕获逻辑。
以下是从实际开发出发的几种有效方式:
✅ 将普通函数转为 async 函数并主动处理 await 错误
普通函数若内部调用异步操作(如 fetch、wx.request、数据库查询),需显式升级为 async,并在每个 await 前加 try-catch 或使用错误元组模式。
// 普通同步函数(无法 await)
function getUser(id) {
return db.find({ id }); // 同步调用,或返回 Promise 但不 await
}
// 升级为 async 函数,并安全 await
async function safeGetUser(id) {
try {
const user = await db.find({ id });
if (!user) throw new Error('User not found');
return user;
} catch (err) {
console.error(`Failed to get user ${id}:`, err);
throw err; // 或返回默认值、封装错误等
}
}
- 所有
await必须在try块内,否则拒绝的 Promise 会变成未捕获异常。 - 不要遗漏
return,避免 Promise 脱离函数上下文导致错误丢失。
✅ 使用 to() 工具函数替代重复 try-catch
这是 Go 风格的错误处理模式,用一个轻量函数把 Promise 转成 [error, data] 元组,让错误检查变成同步判断。
// to.js(可自行实现,15 行以内)
export function to(promise) {
return promise
.then(data => [null, data])
.catch(err => [err, null]);
}
// 使用示例
import { to } from './to.js';
async function fetchProfile(userId) {
const [err, user] = await to(api.getUser(userId));
if (err) return { success: false, error: err.message };
const [err2, posts] = await to(api.getPosts(user.id));
if (err2) return { success: false, error: err2.message };
return { success: true, data: { user, posts } };
}
- 优势:消除嵌套
try-catch,逻辑扁平,适合多步依赖异步调用。 - 注意:仍需手动检查
err,不可省略判断。
✅ 在框架层统一包装 async 中间件(如 Express、Koa、小程序)
避免每个路由都写 try-catch,用高阶函数自动捕获并交给错误处理器。
// Express 中的 asyncHandler 包装器
const asyncHandler = fn => (req, res, next) =>
Promise.resolve(fn(req, res, next)).catch(next);
// 路由中直接写 async,无需 try-catch
app.get('/user/:id', asyncHandler(async (req, res) => {
const user = await safeGetUser(req.params.id);
res.json(user);
}));
-
next(err)触发全局错误中间件,实现集中日志、状态码设置、响应格式统一。 - 小程序中类似:对
wx.request封装后的 Promise 做.catch(next)处理。
✅ 监听全局未捕获拒绝作为兜底防线
即使做了上述所有,仍可能漏掉某些 Promise(如事件回调、定时器中的异步操作)。加一层防御:
// Node.js 环境
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
// 上报监控系统、记录日志、避免进程退出(视场景决定)
});
// 浏览器环境
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled rejection:', event.reason);
event.preventDefault(); // 阻止默认控制台警告(谨慎使用)
});
- 这不是替代方案,而是最后一道保险——应尽量让错误在业务层被捕获。
不复杂但容易忽略











