在装饰器中使用 async 与 await 的核心做法是:让装饰器函数返回一个包装后的异步函数,并在该包装函数内部使用 await 调用原始方法。这样可以在不改变原始方法签名的前提下,拦截并处理异步逻辑,例如执行前置检查、记录日志或处理返回值。

如何定义支持异步方法的装饰器结构
定义装饰器时,需要确保返回的函数也是 async 函数,以便能够使用 await。如果原始方法是同步的,直接调用即可;如果是异步的,必须等待其 Promise 状态解决。这种结构允许我们在方法执行前后插入自定义逻辑。

function asyncDecorator(target, key, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args) {
console.log('Before method execution');
try {
// 调用原始异步方法
const result = await originalMethod.apply(this, args);
console.log('After method execution');
return result;
} catch (error) {
console.error('Error occurred:', error);
throw error;
}
};
return descriptor;
}
上述代码展示了一个标准的异步装饰器模板。它捕获了原始方法,替换为一个新的异步函数。在新函数中,await 用于等待 originalMethod 完成。这确保了装饰器逻辑能正确感知异步操作的完成时间。
如何处理异步方法中的错误与返回值
当被装饰的方法是异步的时,任何未捕获的错误都会导致 Promise 拒绝。因此,在装饰器内部使用 try...catch 块包裹 await 调用至关重要。这样可以统一处理异常,避免错误传播到调用者那里造成不可控的行为。同时,必须显式返回 await 的结果,以保持数据流的完整性。

class DataService {
@asyncDecorator
async fetchData(url) {
if (!url) throw new Error('URL is required');
return { data: 'mocked', url };
}
}
const service = new DataService();
service.fetchData('http://example.com').then(res => console.log(res));
// 输出:
// Before method execution
// After method execution
// { data: 'mocked', url: 'http://example.com' }
在这个示例中,DataService 类的方法 fetchData 被装饰。当调用 fetchData 时,装饰器先打印“Before”,然后等待网络请求(模拟)完成。如果成功,打印“After”并返回数据。如果抛出错误,如 URL 为空,装饰器会捕获错误并重新抛出,但在此之前记录了错误信息。
基于输入参数校验的具体问题
在实际应用中,经常需要在异步方法执行前验证输入参数的有效性。例如,如果 fetchData 需要一个有效的字符串 URL,我们可以在装饰器中添加参数校验逻辑。如果参数无效,可以直接抛出错误或返回默认值,从而避免不必要的异步操作。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











