I'm trying to Proxy a Promise in native Firefox (and using Babel).
var prom = new Promise(function(resolve, reject){resolve(42)});
var promProxy = new Proxy(prom, {});
promProxy.then(function(response){console.log(response)});
I'm trying to Proxy a Promise in native Firefox (and using Babel).
var prom = new Promise(function(resolve, reject){resolve(42)});
var promProxy = new Proxy(prom, {});
promProxy.then(function(response){console.log(response)});
This doesn't work, I get 'TypeError: 'then' called on an object that does not implement interface Promise.'
Share Improve this question asked Jun 13, 2015 at 13:35 samsam 3,9383 gold badges23 silver badges20 bronze badges 1- Why are you trying this? Indeed, a proxy for a promise is not a native promise object. Maybe you were looking for subclassing? – Bergi Commented Jul 10, 2015 at 21:47
3 Answers
Reset to default 10You need to have your handler implement the get() trap and return the bound version of prom.then
var prom = new Promise(function(resolve, reject){resolve(42)});
var promProxy = new Proxy(prom, {
get: function(target, prop) {
if (prop === 'then') {
return target.then.bind(target);
}
}
});
promProxy.then(function(response){console.log(response)});
Note that if you simply want to proxy all accessors, the get
function would look like this:
var promProxy = new Proxy(prom, {
get: function(target, prop) {
var value = target[prop];
return typeof value == 'function' ? value.bind(target) : value;
}
});
bind
will ensure the function won't be incorrectly called when you're dealing with Native objects such as Promises, or the console.
EDIT: In some instances browsers / node will have an outdated version of Proxies, in which case you'll want to use harmony-reflect to bring it up to date.
Hmm, this question is How to Proxy a Promise. I arrived here looking for How to Promise a Proxy -- or maybe more precisely, How to resolve a Proxy. I suspect others may land here, too, so I'll post this here, just in case.
I already have a nice working proxy object, and then I go and try to wrap it in a promise:
var p = new Promise(function(resolve, reject) {
var proxy = get_my_proxy();
resolve(proxy);
});
And wouldn't you know it, then darn resolve method asks my proxy for a then
property (which is unexpected by my proxy logic, causing it to throw). It may not be ideal, depending on what your proxy is for, but here's how I worked around this (and appropriately enough, as my question is the inverse of this one, my solution is the inverse as well) -- by returning null
for then
-- thereby letting resolve()
know that I didn't pass it a Promise
(aka Thenable
).
get: function(target, prop) {
if (prop === 'then') return null; // I'm not a Thenable
// ...the rest of my logic
}
You can deal with the fact then
is not called on a promise but on a proxy by wrapping any function properties of the proxy in a companion proxy for functions that resolves the proxied object before applying.
const targetProp = Symbol('target');
const promProxy = createObjectProxy(Promise.resolve(42))
promProxy.then((response) => { console.log(response); }); // 42
promProxy.then.call(Promise.resolve(37), (response) => { console.log(response); }); // 37
function createObjectProxy(object) {
return new Proxy(object, {
get(target, prop, receiver) {
if (prop === targetProp) {
return target;
}
const value = Reflect.get(target, prop, receiver);
if (typeof value === 'function') {
return createFunctionProxy(value);
};
return value;
}
});
}
function createFunctionProxy(method) {
return new Proxy(method, {
apply(target, thisArg, argumentsList) {
thisArg = Reflect.get(thisArg, targetProp) ?? thisArg;
return Reflect.apply(target, thisArg, argumentsList);
}
});
}
While binding does the job in most cases, in some cases you may want to preserve the ability to call a function property on a different object than the one used to look it up.