9

I am compiling the code with babel (env), compiling down to ES5.

Here's the code:

(async () => {
     const p = async () => {
          return new Proxy({}, {
               get: (target, property) => {
                    console.log(property);
               }
          })
     };

     const r = await p();// await calls .then on the result of p()
})();
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
millsp
  • 1,259
  • 1
  • 10
  • 23
  • 1
    It is not because of `await`. This happens if `p` is invoked. – thefourtheye Jan 18 '18 at 11:04
  • Yes, you are right, the Proxy just helped to see this behaviour ! Calling an async causes '.then()' to be called on the return / result. So if the return result it's an Object, .then() will be called on it. It seems that this behaviour is used to cascade nested promises. What now ? How can we avoid this behaviour ? I blacklisted '.then' inside of my Proxy, but it's not the best. @thefourtheye – millsp Jan 18 '18 at 11:41
  • 1
    @Pirix Why would you want to avoid it? This is how promises and async functions work. What's the purpose of your proxy in the first place? – Bergi Jan 18 '18 at 12:26
  • @Bergi The async function causes to call .then() on it's result / return (if it's an Object). This should only happen when returning an async/promise. – millsp Jan 18 '18 at 12:38
  • 2
    @Pirix And how do you think the async function knows that you are `return`ing an "async/promise"? – Bergi Jan 18 '18 at 12:50
  • @Bergi with an instanceof Promise. I don't see anywhere in the specs that an **async** function must call **.then()** on it's return value. And I see that **await** must resolve the result / return of a **promise/async**. So yes it resolves the result but calls .then() on it – millsp Jan 18 '18 at 13:01
  • 2
    `await` is supposed to be used on a *thenable*, it makes no sense to "await" something else, so your function needs to always return a promise. Calling `.then` is what *resolving the result* means. It's not `async` the calls `.then`, it's `await` that does it in order to get the resolved value. – Lennholm Jan 18 '18 at 13:01
  • @MikaelLennholm the _thenable_ is the async function itself. So I await the result of it which is my proxy. – millsp Jan 18 '18 at 13:07
  • No, the *thenable* is what your async function returns. `await` interprets your proxy as a wrapped thenable and resolves that as well. If it didn't do that, it wouldn't be compatible with promises – Lennholm Jan 18 '18 at 13:09

1 Answers1

7

It's actually happening twice.

Why is .then() triggered on a Proxy returned by an async function?

The result of an async function call is a promise that is resolved with the return value from the function body evaluation. Resolving a promise checks whether the resolution value is a thenable ("promise-like value"), which would lead to the promise waiting for the inner result. (In your case, accessing .then on the proxy does not return a function, so it's not considered a thenable and the promise is fulfilled with the proxy).

Why does await trigger .then() on a Proxy?

Same here. await does not work only with promises, it works on arbitrary values. To determine their "promise-worthiness", it runs exactly the same thenable check - it resolves a promise with the awaited value and then waits for the promise to settle.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375