proxy 可实现异步懒加载:首次访问属性时返回 promise 并发起请求,后续访问直接返回缓存结果;通过 map 缓存 promise、约定字段标记、避免 get 中 await,支持 await 读取和错误处理。

Proxy 可以通过拦截 get 操作,在首次访问某个属性时才触发异步加载,之后缓存结果,实现真正的异步懒加载。关键在于:用 Promise 占位、避免重复请求、支持 await 直接读取、处理加载中与错误状态。
用 Promise 占位 + 缓存结果
初次访问属性时,不立即返回值,而是返回一个 Promise,并发起异步操作(如 fetch);后续访问直接返回已解析的值或缓存的 Promise,确保只加载一次。
- 用私有 Map 或闭包对象缓存 Promise 实例(防止不同属性互相干扰)
- 对已 resolve 的 Promise,再次 .then() 仍能拿到值,天然适合多次读取
- 不要在 get 中 await —— 否则会阻塞整个属性读取,失去“懒”和“异步”意义
拦截 get 并动态创建加载逻辑
在 handler.get 中判断属性是否存在、是否为待加载字段,再决定返回缓存值、加载 Promise 或 throw 提示。
- 可约定特殊前缀(如
_async_)或白名单数组标记懒加载字段 - 检查缓存 map 是否已有该 key 对应的 Promise;没有就调用 loader 函数并存入
- loader 函数应接收属性名,返回 Promise,便于复用和测试
支持 await 访问和同步风格写法
因为返回的是 Promise,所以使用者可直接 await obj.prop;若想“假装同步”,可用 obj.prop.then(...) 或顶层 await(模块级)。
- 无需额外封装 getter 方法,语法干净:
const user = await api.user; - 错误会被 Promise reject 捕获,可用 try/catch 或 .catch() 处理
- 加载中状态隐含在 pending Promise 中,如需显式控制(如 loading UI),可扩展返回 { loading, data, error } 对象
简单可运行示例
(仅核心逻辑,无错误重试等增强)
function createLazyProxy(loader) {
const cache = new Map();
return new Proxy({}, {
get(target, prop) {
if (prop === 'then') return undefined; // 防止被误判为 thenable(非必需,但更健壮)
if (!cache.has(prop)) {
cache.set(prop, loader(prop).catch(err => { throw err; }));
}
return cache.get(prop);
}
});
}
// 使用
const api = createLazyProxy(async (key) => {
if (key === 'user') return fetch('/api/user').then(r => r.json());
if (key === 'posts') return fetch('/api/posts').then(r => r.json());
});
// 在 async 函数中使用
async function demo() {
const user = await api.user; // 第一次:触发请求
const posts = await api.posts; // 第一次:触发请求
const user2 = await api.user; // 第二次:直接返回缓存 Promise 的结果
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











