Async functions not friendly to promise extensions

# medikoo (7 years ago)

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: mozilla.6506.n7.nabble.com/Async-functions-not-friendly-to-promise-extensions-tp364921.html Sent from the Mozilla - ECMAScript 4 discussion mailing list archive at Nabble.com.

# Matthias welp (7 years ago)

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" <medikoo+mozilla.org at medikoo.com> 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 mozilla.6506.n7.nabble.com/Async-functions-not-friendly-to-promise-extensions-tp364921.html

Sent from the Mozilla - ECMAScript 4 discussion mailing list archive mozilla.6506.n7.nabble.com/Mozilla-ECMAScript-4-discussion-f89340.html

at Nabble.com.

# medikoo (7 years ago)

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?

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

# Matthias welp (7 years ago)

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.

# medikoo (7 years ago)

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

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

# T.J. Crowder (7 years ago)

...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.:

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:

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

# Isiah Meadows (7 years ago)

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 me at isiahmeadows.com