10

According to Mozilla, await only awaits Promises:

[rv] Returns the resolved value of the promise, or the value itself if it's not a Promise.

If you await a non-Promise, a resolved promise will be immediately returned, and it will not await. However, the following code awaits without using Promises in Chrome & FF.

var obj = {
    then:func => obj.func=func
};
setTimeout(() => obj.func(57), 1000);

async function go() {
    var res = await obj;
    console.log(res); //shows '57' after 1000ms
}

go();

According to the specs, should await await promise-like objects that are not Promises? (I tried looking at the specs (linked from the Mozilla article), but I couldn't understand it.)

wezten
  • 2,126
  • 3
  • 25
  • 48
  • Main question what is Promise for ES-transpiler/interpretator, which performs await operation. For example, you can use bluebird promises, but babel in default configuration will not understand it. One of main definition is `promise === Promise.resolve(promise)`, but transpiler can't see it in compile-time. – Vladislav Ihost Jul 18 '17 at 11:32
  • Most likely, in practice, Promise is some thingy, which meant by Promise by regenerator-runtime, which is widely used implementation for this. See here https://babeljs.io/docs/plugins/transform-async-generator-functions/ for details. – Vladislav Ihost Jul 18 '17 at 11:34
  • 1
    Actually it does use promises, you just don't see them :-) Btw, those "promise-like objects" are also called [*thenables*](https://stackoverflow.com/q/29435262/1048572). – Bergi Jul 19 '17 at 03:36
  • 1
    @Bergi The question you linked it to is not related, because that was about awaiting numbers, not `thenables`. My question is: is awaiting `thenables` in the spec? – wezten Jul 19 '17 at 17:41
  • 1
    @wezten The answer explains what happens to every awaited value, be it a promise, number or thenable. `Promise.resolve` deals with thenables - yes, it's in the spec. – Bergi Jul 20 '17 at 05:34
  • 1
    @Bergi Where in that answer does it talk about `thenables`? All that answer shows is that `await obj == await Promise.resolve(obj)`, but I cannot tell whether `Promise.resolve(obj)` will return a resolved promise of `obj` as is, or whether it detects that it has a `then` property, and returns an unresolved promise that waits for the callback passed to `then` to be called. – wezten Jul 20 '17 at 07:05
  • @wezten OK, I assumed you knew what `Promise.resolve` does. See [What should happen if you resolve a promise with another promise?](https://stackoverflow.com/q/34964819/1048572), [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve#Resolving_thenables_and_throwing_Errors) or [Promises/A+](https://promisesaplus.com/) – Bergi Jul 20 '17 at 09:02
  • @Bergi No! I'm looking for `What should happen if you resolve a promise with a thenable?` All I'm looking for is a link to the specs confirming that a thenable is treated like a promise, even though it's not. – wezten Jul 21 '17 at 09:55
  • @wezten I already linked the Promises/A+ specification (the very source of the "thenable" interoperability idea), the relevant part of the ES6 spec can be found [here](http://www.ecma-international.org/ecma-262/6.0/#sec-promise-resolve-functions) – Bergi Jul 21 '17 at 12:17
  • @Bergi Thanks. So `await` calls `Promise.resolve` on the parameter, and the spec involving resolving promises clearly looks for a `then` function, and passes it a callback if so. Glad to know that I can rely on this behavior, and it's not just a browser thing. If you put this in an answer I'll accept it. – wezten Jul 23 '17 at 14:51

2 Answers2

5

await is going to trigger obj.then(), and that's causing that behavior. Because even if obj is not a Promise, is a thenable object.

You have some information about that here.

In your case it works because:

First tick

  1. obj is initialized
  2. setTimeout() is executed, its callback will be called in the next tick
  3. go() is declared
  4. go() is executed
  5. await is triggered inside go(), which executes obj.then(), assigning the resolving function to obj.func
  6. it has not been resolved yet so the tick ends here

Second tick

  1. setTimeout() callback is executed, resolving the promise through obj.func() with the value 57

Third tick

  1. the control is back to go(), and the result 57 is logged
Antonio Val
  • 3,200
  • 1
  • 14
  • 27
  • 5
    I wrote it, so I understand why it works. My question is does it say in the specs that `await` should examine the object for a `then` property if it is not a `Promise`, or is this something that the browsers implemented that is not in the specs? – wezten Jul 19 '17 at 17:36
0

From that same page:

If the value is not a Promise, it converts the value to a resolved Promise, and waits for it.

The value will thus automatically be converted to a resolved Promise, and then be waited for.

Jacques Marais
  • 2,666
  • 14
  • 33
  • 4
    However in my example, an unresolved promise is returned, since it waits another 1000ms. If it would be resolved, it would return immediately. What that page means is that the parameter is returned immediately as is, so in my example it would return `{then:func => obj.func=func}`, not `57` - see the example there. – wezten Jul 18 '17 at 14:05