用Proxy模拟虚拟对象,await触发then属性时Getter应返回什么?
首先得搞清楚为什么await myProxy会触发then属性的get调用:await操作符会自动检查右侧的值是否是「thenable」(即拥有then方法的对象)。对于普通对象来说,它没有then属性,所以await会直接把它包装成一个resolved状态的Promise,值就是对象本身;但Proxy不一样——当JS尝试读取then属性时,会直接触发你的Proxy getter陷阱,这就是你看到的现象。
接下来回答你的核心问题:getter在处理then属性时应该返回什么?
绝对不要返回Proxy自身
如果你的getter在访问then时返回Proxy自身,一定会报错——因为JS会尝试调用这个then属性,但Proxy本身不是函数,会直接抛出TypeError: then is not a function。比如下面的错误示例:
const badProxy = new Proxy({}, { get(target, prop) { if (prop === 'then') { return badProxy; // ❌ 错误:返回自身,不是可调用的函数 } return '就绪值'; } }); // 执行await会报错 (async () => { try { await badProxy; } catch (e) { console.error(e); // TypeError: badProxy.then is not a function } })();
正确的做法:返回一个能resolve自身的then方法
你需要让Proxy成为一个合法的thenable对象,也就是在getter中返回一个符合Promise规范的then函数,这个函数会把Proxy自身作为resolved的值传递出去。这样await myProxy的结果就会是Proxy对象本身,和普通对象的await行为完全一致。
这里有两种简洁的实现方式:
方式1:自定义then函数
直接返回一个手动实现的then方法,明确resolve当前Proxy:
const myProxy = new Proxy({}, { get(target, prop, receiver) { if (prop === 'then') { // receiver就是当前的Proxy实例 return (resolve) => resolve(receiver); } // 其他属性返回你的就绪值 return '就绪值'; } }); // 测试await (async () => { const result = await myProxy; console.log(result === myProxy); // ✅ true })();
方式2:借用Promise的then方法
利用Promise.resolve()快速生成一个resolved状态的Promise,直接复用它的then方法,效果和上面一致:
const myProxy = new Proxy({}, { get(target, prop) { if (prop === 'then') { return Promise.resolve(myProxy).then; } return '就绪值'; } }); (async () => { const result = await myProxy; console.log(result === myProxy); // ✅ true })();
总结
通过在getter陷阱中正确处理then属性,返回一个能resolve自身的then函数,你的Proxy在await时的表现就会和普通对象完全一致——既保留了其他属性返回就绪值的逻辑,又能让await myProxy正确得到Proxy实例本身。
内容的提问来源于stack exchange,提问作者user2106769

