如何实现支持同步/异步回调的通用failSafe函数?
通用兼容同步/异步的错误捕获函数实现思路
核心思路是利用async/await的特性,统一处理同步函数和异步函数的执行与错误捕获,同时返回一致的结果格式,让调用方无需区分函数类型。
基础实现方案
直接封装一个高阶函数,内部通过try/catch捕获同步错误,借助await自动处理异步Promise的resolve/reject,最终返回包含错误和结果的统一格式(这里用[error, result]数组,你也可以换成对象格式):
function failSafe(fn) { return async function(...args) { try { // 执行传入的函数,不管同步还是异步 const result = fn(...args); // await兼容同步值(直接返回)和Promise(等待完成) return [null, await result]; } catch (err) { // 捕获同步抛出的错误,或await Promise时的reject错误 return [err, null]; } }; }
测试用例验证
同步函数场景
// 同步函数:输入负数抛出错误 const syncDouble = (num) => { if (num < 0) throw new Error("不允许输入负数"); return num * 2; }; const safeSyncDouble = failSafe(syncDouble); // 调用方式统一用await (async () => { console.log(await safeSyncDouble(6)); // [null, 12] console.log(await safeSyncDouble(-2)); // [Error: 不允许输入负数, null] })();
异步函数场景
// 异步函数:输入负数reject const asyncDouble = async (num) => { if (num < 0) throw new Error("不允许输入负数"); // 模拟异步操作 return new Promise(resolve => setTimeout(() => resolve(num * 2), 100)); }; const safeAsyncDouble = failSafe(asyncDouble); safeAsyncDouble(8).then(console.log); // [null, 16] safeAsyncDouble(-5).then(console.log); // [Error: 不允许输入负数, null]
可选优化:自定义错误处理
如果需要对捕获的错误做统一处理(比如格式化、补充信息),可以增加一个错误处理参数:
function failSafe(fn, errorHandler = (err) => err) { return async function(...args) { try { const result = fn(...args); return [null, await result]; } catch (err) { // 调用自定义错误处理函数 const handledError = errorHandler(err); return [handledError, null]; } }; } // 使用示例:将错误转为自定义格式 const safeFn = failSafe(asyncDouble, (err) => ({ code: "INVALID_INPUT", message: err.message })); safeFn(-3).then(console.log); // [{ code: "INVALID_INPUT", message: "不允许输入负数" }, null]
实现原理说明
- 统一执行逻辑:不管传入的是同步还是异步函数,都先执行获取结果。
- await的兼容性:
await不仅能等待Promise完成,遇到非Promise值会直接返回该值,完美兼容同步场景。 - 错误统一捕获:
try/catch既可以捕获同步函数执行时抛出的错误,也能捕获awaitPromise时触发的reject(因为await会把Promise的reject转为抛出错误)。
内容的提问来源于stack exchange,提问作者TOPKAT
相关产品推荐
相关产品推荐

