Quantcast

Async functions not friendly to promise extensions

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Async functions not friendly to promise extensions

medikoo
This post was updated on .
While Promise methods and functions are friendly for it's extensions (or even not direct extensions but just thenables), the async function will always normalize it's result to instance of Promise, even it's ExtendedPromise, e.g.:

class ExtendedPromise extends Promise {};

var extendedPromise = new ExtendedPromise(function (resolve) { resolve(); });
extendedPromise.then().constructor === ExtendedPromise // true

var asyncFn = async function () { return extendedPromise; };
asyncFn().constructor === ExtendedPromise // false
asyncFn().constructor === Promise // true

That makes it cumbersome if we work with promise extensions. What was the reasoning behind such design?
If not thenables in general, the promise extensions I believe should be passed through (or copied via its constructor.resolve).

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Async functions not friendly to promise extensions

Matthias welp
resend/fwd of accidental personal reply


Hello Medikoo,

You seem to misunderstand what async functions do to be async. Your function has the same product as the following:

new Promise((acc, rej) => acc(extendedPromise))

A promise that resolves to a extendedPromise instance. By no means do async functions use the returned values as their way of determining what type of promise they are: that'd break when using multiple returns with different types.

I hope this explains it a bit for you.

-Matthias

On 14 Apr 2017 09:58, "medikoo" <[hidden email]> wrote:
While Promise methods and functions are friendly for it's extensions (or even not direct extensions but just thenables), the async function will always normalize it's result to instance of Promise, even it's ExtendedPromise, e.g.: class ExtendedPromise extends Promise {}; var extendedPromise = new ExtendedPromise(function (resolve) { resolve(); }); extendedPromise.then().constructor === ExtendedPromise // true var asyncFn = async function () { return extendedPromise; }; asyncFn().constructor === ExtendedPromise // false asyncFn().constructor === Promise // true That makes it cumbersome if we work with promise extensions. What was the reasoning behind such design? If not thenables in general, the promise extensions I believe should be passed through (or copied via its constructor.resolve).

View this message in context: Async functions not friendly to promise extensions
Sent from the Mozilla - ECMAScript 4 discussion mailing list archive at Nabble.com.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Async functions not friendly to promise extensions

medikoo
> You seem to misunderstand what async functions do to be async, Your function has the same product as the following:

> new Promise((acc, rej) => acc(extendedPromise))

Yes, I totally understand that, and it's clear to me that it's that way. In my post I question that design, as it seems to me that way nicer would be if it's as follows:

If (isThenable(result)) return result;
else return new Promise((resolve, reject) => resolve(result));

Or if above seems too liberal, then at least:

if (isPromise(result)) return new result.constructor((resolve, reject) => resolve(result));
else return new Promise((resolve, reject) => resolve(result));

> By no means do async functions use the returned values as their way of determining what type of promise
they are: that'd break when using multiple returns with different types.

> I hope this explains it a bit for you.

Sorry, but it didn't explain much. What to you mean by "that'd break when using multiple returns with different types" ? Can you throw some simple example?

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Async functions not friendly to promise extensions

Matthias welp
> I hope this explains it a bit for you.

Sorry, but it didn't explain much. What to you mean by "that'd break when
using multiple returns with different types" ? Can you throw some simple
example?

sure

var k = new Promise((acc, rej) => window.setTimeout(1000, ()=> acc(randomPromiseSubtype)));

~=

var k = (async function() {await window.setTimeout(1000); return randomPromiseSubtype})();

type of var k cannot be determined when the promise is made, due to the timeout not yet having returned. Ahead-of-time determining of type is really impossible with unpure functions, which must be available in async functions (e.g. for fetch). You can wrap your async function call in a custom promise (which would have your desired result), changing promise instance class hierarchies on-the-fly would make promises much less deterministic than what they are now, and would​ introduce confusion: typeof k would change depending on how long your program has run.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Async functions not friendly to promise extensions

medikoo
> var k = (async function() {await window.setTimeout(1000); return randomPromiseSubtype})();

Assuming that setTmeout(1000) returns a promise, this code is equivalent to:

async function() {
    return setTimeout(1000).then(function () {
        return randomPromiseSubtype;
    });
};

I definitely would not expect that k in such case resolves with promise of type of  randomPromiseSubtype, same as you never expect that `setTimeout(1000).then()`may resolve with different promise types.

However if it's:

async function() {
    return randomPromiseSubtypeTimeout(1000).then(function () {
        return whateverPromise;
    });
};

It'll be great if k resolves with promise that shares the constructor with promise returned by randomPromiseSubtypeTimeout(1000).then(...). That's my point

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Async functions not friendly to promise extensions

T.J. Crowder-2
In reply to this post by Matthias welp
 ...that'd break when using multiple returns with different types.

Well, not necessarily. It may have been possible to make the promise the async function returns be of the same type as the first promise it encounters during the synchronous part of its execution (remember that execution is synchronous until the first `await` or `return`). E.g.:

```js
async function foo() {
    console.log("This is the synchronous bit");
    if (someCondition) {
        await a();
    } else {
        await b();
    }
    return await c();
}
```

Assume `a` and `b` return different types of promises. *Conceptually* it would have been possible to make `foo` return a promise of the same type as the one returned by `a` if `someCondition` were true or the same type as `b`'s promise if `someCondition` were false. E.g., as though it were like this:

```js
function foo() {
    console.log("This is the synchronous bit");
    let p;
    if (someCondition) {
        p = a();
    } else {
        p = b();
    }
    return p.then(_ => c());
}
```

That's just not how it's defined in the proposal and upcoming 2017 spec. I don't know if there's some implementational reason that wasn't done, or a philosophical reason, or what. It would certainly be more complex to implement and understand than what's been specified; I'm not surprised simplicity won out.

Re:

> var k = (async function() {await window.setTimeout(1000); return randomPromiseSubtype})();

(Missing a callback there.) In that situation, in our alternate universe where async functions did what medikoo wants, the function would return a promise created by `NewPromiseCapability(%Promise%)`, since the function had to generate its own promise due to awaiting a synchronous function. E.g., the first promise it encountered in its synchronous code would be (effectively) `Promise.resolve(window.setTimeout(callback, 1000))`.

I'm not trying to suggest I think it would have been better. I like simplicity. But I do see what medikoo is getting at, and conceptually I'm not immediately seeing why it *couldn't* have been done that way instead.

-- T.J. Crowder

On Fri, Apr 14, 2017 at 11:53 AM, Matthias welp <[hidden email]> wrote:
> I hope this explains it a bit for you.

Sorry, but it didn't explain much. What to you mean by "that'd break when
using multiple returns with different types" ? Can you throw some simple
example?

sure

var k = new Promise((acc, rej) => window.setTimeout(1000, ()=> acc(randomPromiseSubtype)));

~=

var k = (async function() {await window.setTimeout(1000); return randomPromiseSubtype})();

type of var k cannot be determined when the promise is made, due to the timeout not yet having returned. Ahead-of-time determining of type is really impossible with unpure functions, which must be available in async functions (e.g. for fetch). You can wrap your async function call in a custom promise (which would have your desired result), changing promise instance class hierarchies on-the-fly would make promises much less deterministic than what they are now, and would​ introduce confusion: typeof k would change depending on how long your program has run.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Async functions not friendly to promise extensions

Isiah Meadows-2
I can't seem to find the exact issue, but I recall V8 wishing they
could single out native Promises for this proposed change (which is
really more of an optimization than a feature), but it ultimately got
rejected for consistency reasons I think.

Google's failing me on finding this, though, or I would link my source here.
-----

Isiah Meadows
[hidden email]


On Fri, Apr 14, 2017 at 7:17 AM, T.J. Crowder
<[hidden email]> wrote:

>>  ...that'd break when using multiple returns with different types.
>
> Well, not necessarily. It may have been possible to make the promise the
> async function returns be of the same type as the first promise it
> encounters during the synchronous part of its execution (remember that
> execution is synchronous until the first `await` or `return`). E.g.:
>
> ```js
> async function foo() {
>     console.log("This is the synchronous bit");
>     if (someCondition) {
>         await a();
>     } else {
>         await b();
>     }
>     return await c();
> }
> ```
>
> Assume `a` and `b` return different types of promises. *Conceptually* it
> would have been possible to make `foo` return a promise of the same type as
> the one returned by `a` if `someCondition` were true or the same type as
> `b`'s promise if `someCondition` were false. E.g., as though it were like
> this:
>
> ```js
> function foo() {
>     console.log("This is the synchronous bit");
>     let p;
>     if (someCondition) {
>         p = a();
>     } else {
>         p = b();
>     }
>     return p.then(_ => c());
> }
> ```
>
> That's just not how it's defined in the proposal and upcoming 2017 spec. I
> don't know if there's some implementational reason that wasn't done, or a
> philosophical reason, or what. It would certainly be more complex to
> implement and understand than what's been specified; I'm not surprised
> simplicity won out.
>
> Re:
>
>> var k = (async function() {await window.setTimeout(1000); return
>> randomPromiseSubtype})();
>
> (Missing a callback there.) In that situation, in our alternate universe
> where async functions did what medikoo wants, the function would return a
> promise created by `NewPromiseCapability(%Promise%)`, since the function had
> to generate its own promise due to awaiting a synchronous function. E.g.,
> the first promise it encountered in its synchronous code would be
> (effectively) `Promise.resolve(window.setTimeout(callback, 1000))`.
>
> I'm not trying to suggest I think it would have been better. I like
> simplicity. But I do see what medikoo is getting at, and conceptually I'm
> not immediately seeing why it *couldn't* have been done that way instead.
>
> -- T.J. Crowder
>
> On Fri, Apr 14, 2017 at 11:53 AM, Matthias welp <[hidden email]> wrote:
>>
>> > I hope this explains it a bit for you.
>>
>> Sorry, but it didn't explain much. What to you mean by "that'd break when
>> using multiple returns with different types" ? Can you throw some simple
>> example?
>>
>>
>> sure
>>
>> var k = new Promise((acc, rej) => window.setTimeout(1000, ()=>
>> acc(randomPromiseSubtype)));
>>
>> ~=
>>
>> var k = (async function() {await window.setTimeout(1000); return
>> randomPromiseSubtype})();
>>
>> type of var k cannot be determined when the promise is made, due to the
>> timeout not yet having returned. Ahead-of-time determining of type is really
>> impossible with unpure functions, which must be available in async functions
>> (e.g. for fetch). You can wrap your async function call in a custom promise
>> (which would have your desired result), changing promise instance class
>> hierarchies on-the-fly would make promises much less deterministic than what
>> they are now, and would introduce confusion: typeof k would change depending
>> on how long your program has run.
>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> [hidden email]
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Loading...