# Promises vs Proxies

**URL:** <https://es.discourse.group/t/promises-vs-proxies/762>\
**Category:** I have questions\
**Tags:** proxy\
**Created:** [May 4, 2021, 8:57am UTC](https://es.discourse.group/t/promises-vs-proxies/762 "2021-05-04T08:57:32Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![hopjs](https://avatars.discourse-cdn.com/v4/letter/h/9f8e36/32.png) [@hopjs](https://es.discourse.group/u/hopjs)\
**Post date:** [May 4, 2021, 8:57am UTC](https://es.discourse.group/t/promises-vs-proxies/762/1 "2021-05-04T08:57:32Z")

</div>

Hi,

I'm puzzled by the interaction between Promises and Proxy objects.  
I'm trying the run the following code:

```javascript
const prom = new Promise( (res, rej) => res( 34 ) );
const xprom = new Proxy( prom, {} );

Promise.prototype.then.call( xprom, val => console.log( val ) );

```

It fails with the error message:

```javascript
proxy.js:5
Promise.prototype.then.call( xprom, val => console.log( val ) );
                       ^

TypeError: Method Promise.prototype.then called on incompatible receiver [object Object]
    at Proxy.then (<anonymous>)
    at Object.<anonymous> (proxy.js:5:24)
    at Module._compile (node:internal/modules/cjs/loader:1108:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
    at Module.load (node:internal/modules/cjs/loader:973:32)
    at Function.Module._load (node:internal/modules/cjs/loader:813:14)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)
    at node:internal/main/run_main_module:17:47

```

If I understand correctly, this is conform to the ECMASpefication that  
defines Promise.prototype.then as:

```javascript
27.2.5.4 Promise.prototype.then ( onFulfilled, onRejected )

When the then method is called with arguments onFulfilled and onRejected, the following steps are taken:

    1. Let promise be the this value.
    2. If IsPromise(promise) is false, throw a TypeError exception.

```

and isPromise is defined as :

```javascript
27.2.1.6 IsPromise ( x )

The abstract operation IsPromise takes argument x. It checks for the promise brand on an object. It performs the following steps when called:

    1. If Type(x) is not Object, return false.
    2. If x does not have a [[PromiseState]] internal slot, return false.
    3. Return true.

```

I'm not quite sure about the [[PromiseState]] but my guess is that  
this designates only "builtin" Promise objects.

The problem I see with 27.2.1.6, is that it creates a means a program  
may use to distinguish plain values from proxies values. I though that  
the whole Proxy design was intended to make this impossible. My  
question is then the following:

Is there a reason for which Promise.prototype.then (and all the  
other Promise.protype methods) _must_ behave differently for promises and  
proxy objects or could Promise.prototype.then be modified so that it is  
also able to handle proxy objects?

The reason for that question is the following. We are trying to build  
a tool for debugging Typecript programs. Our idea is to map TypeScript  
types to higher-order contracts and to execute them with dynamic  
verification. These higher-order contracts are implemented with  
proxies. So far, we are able to cope with all the TypeScript  
constructs but promises because of the aformentionned problem.

I thank you in advance for your help or explanations.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [May 4, 2021, 1:50pm UTC](https://es.discourse.group/t/promises-vs-proxies/762/2 "2021-05-04T13:50:01Z")

</div>

> [@hopjs](#):
>
> The problem I see with 27.2.1.6, is that it creates a means a program  
> may use to distinguish plain values from proxies values. I though that  
> the whole Proxy design was intended to make this impossible.

Proxies are not designed to be 'invisible'. You can see the same thing with [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)

```javascript
const s = new Set(['a']);
s.has('a'); // true
Set.prototype.has.call(s, 'a'); // true

const p = new Proxy(s, {});
p.has('a'); // TypeError!
Set.prototype.has.call(p, 'a'); // TypeError!

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [May 4, 2021, 2:21pm UTC](https://es.discourse.group/t/promises-vs-proxies/762/3 "2021-05-04T14:21:34Z")

</div>

Every builtin except Error and Proxy has a robust way to identity it, usually via a prototype method that throws. Internal slots and private fields don’t “tunnel” through a Proxy, so a proxy for any builtin with slots (or any object that exposes an identity-based detection mechanism) is thus trivially detectable as such.

---

<div class="post-metadata">

**Author:** ![hopjs](https://avatars.discourse-cdn.com/v4/letter/h/9f8e36/32.png) [@hopjs](https://es.discourse.group/u/hopjs)\
**Post date:** [May 4, 2021, 3:31pm UTC](https://es.discourse.group/t/promises-vs-proxies/762/4 "2021-05-04T15:31:17Z")

</div>

Thank you for these explanations. I realize that I was wrong assuming the "invisibility" of proxy objects.  
However, to get back to my question, Is there a reason for which Promise.then _should not_ accept  
proxys (or is it just because it's one method among many others)?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [May 4, 2021, 4:31pm UTC](https://es.discourse.group/t/promises-vs-proxies/762/5 "2021-05-04T16:31:50Z")

</div>

Because a Proxy doesn’t have the internal slots of a Promise.

A Proxy can certainly be a thenable, but Promise.prototype.then can’t be used unless the receiver is a proper Promise.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [May 4, 2021, 4:47pm UTC](https://es.discourse.group/t/promises-vs-proxies/762/6 "2021-05-04T16:47:36Z")

</div>

To add to what @ljharb has already said.

For `Promise.prototype.then` or any method that references internal/private state to work on a proxy version of the object there would need to be an api like `Proxy.getOriginalObject(proxy)`, and this is the bit that would defeat the design of Proxy.

---

<div class="post-metadata">

**Author:** ![hopjs](https://avatars.discourse-cdn.com/v4/letter/h/9f8e36/32.png) [@hopjs](https://es.discourse.group/u/hopjs)\
**Post date:** [May 4, 2021, 5:10pm UTC](https://es.discourse.group/t/promises-vs-proxies/762/7 "2021-05-04T17:10:45Z")

</div>

I imagine that this should be doable using a new proxy handler method but I think I understand now why  
it would be bad idea to add a proxy support directly in "Promise.prototype.then". Thanks for your time and your explanations.
