Async Class

# Dimitrian Nine (10 months ago)

I cant find: was or not that proposal...

But can we have Async Class with async constructor and async super?

//AsyncClass
async_class AsyncClass { // keyword async_class(example)
constructor() {
await something(); // now constructor async too
}}

//AsyncObj in some async method
let NewAsyncObj = await AsyncClass(); // create async obj

//Extends
async_class ExtAsyncClass extends AsyncClass{
constructor() {
await super(); // now we can await super too
await something();
}}
# Isiah Meadows (10 months ago)

Is an async factory function/method not sufficient to do this? Also, note that you can return promises out of the constructor (and I've done it before).

Isiah Meadows me at isiahmeadows.com

Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com

# Dimitrian Nine (10 months ago)

"Is an async factory function/method not sufficient to do this?"

Maybe, but i think it question similiar to "factory vs class": we can use Сlass now, but why not to extend it to Async then?

"Also, note that you can return promises out of the constructor (and I've done it before)"

Like callback? Maybe, but again it simillial to "await vs callback" then.

I just like Class,Async and Await patterns. And think:this some sugar can be useful for some people like me...

# T.J. Crowder (10 months ago)

On Fri, Feb 16, 2018 at 7:51 AM, Dimitrian Nine <dimtimeforever at gmail.com>

wrote:

"Also, note that you can return promises out of the constructor (and I've

done it before)"

Like callback?

I think he means literally returning a promise. If you return an object out of the constructor, that becomes the result of the new operation. So you can literally return a promise of an instance instead of an instance (fiddle):

class Example {
    constructor() {
        return new Promise(resolve => {
            setTimeout(() => {
                const instance = Object.create(Example.prototype);
                resolve(instance);
            }, 200);
        });
    }

    foo() {
        console.log("foo called");
    }
}

It gets ugly(ier) when you want to extend that. :-)

-- T.J. Crowder

# Isiah Meadows (10 months ago)

I think he means literally returning a promise.

That would be the correct assumption. ;-)

Isiah Meadows me at isiahmeadows.com

Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com

# Dimitrian Nine (10 months ago)

"It gets ugly(ier) when you want to extend that. :-) "

Ok, i get it, but yes i prefer some more sugar like as i suggested before.

async class Files{
constructor(path){
this.blob = await get_file(path);
}}

async class ExtFiles extends Files{
constructor(path){
await super(path);
this.path = path;
}}

[file1,file2,file3] = await Promise.all([
new ExtFiles(path1),
new ExtFiles(path2),
new ExtFiles(path3)
]);
# Naveen Chawla (10 months ago)

You can just call an async method from the constructor (without await) - and then let that async method handle all the asynchronicity.

Does this satisfy your use case?

I think async constructor would make more sense than async class. Calling new MyObjectAsync() would have to return a promise for the object, requiring await to actually get the object.

My only reservation is that it does require caution not to presume that new X() isn't actually an instance of X (but that await new X() is). Otherwise I don't mind it.

# Dimitrian Nine (10 months ago)

"You can just call an async method from the constructor (without await) - and then let that async method handle all the asynchronicity."

Not sure about it - how control? callback? I prefer async/await then.

"I think async constructor would make more sense than async class"

Maybe: i use it for class more for difference between class and async class was more visible. But yes in total idea about async constructor. Both variants work for me. What more useful - i dont sure...

# Naveen Chawla (10 months ago)

Like this:

class MyObject{
    constructor(){
        initializeAsync();
    }

    async initializeAsync(){
        await doSomething();
        await doSomethingElse();
        //etc.
    }
}

Of course if you wanted to await at the constructor call level (and await inside the constructor itself), e.g.

    const myObject = await new MyObject();

...then of course you would need the "async constructor" feature, like you've requested, but then new MyObject() would return a promise.

Personally I have no problem with this:

It suffers from the same bug-set than you would get if you converted a synchronous function to an asynchronous one (i.e. the need to await).

# T.J. Crowder (10 months ago)

On Sun, Feb 18, 2018 at 8:27 AM, Naveen Chawla <naveen.chwl at gmail.com>

wrote:

Like this:

class MyObject{
    constructor(){
        initializeAsync();
    }

    async initializeAsync(){
        await doSomething();
        await doSomethingElse();
        //etc.
    }
}

That constructor breaks one of the main rules of promises: Either handle the rejection, or propagate the promise.

-- T.J. Crowder

# Naveen Chawla (10 months ago)

There is no rule that says you must propagate every promise. initializeAsync doesn't return anything, so the constructor just kicks off the async process.

# Naveen Chawla (10 months ago)

In the example, promise rejection can be handled with a try+catch inside initializeAsync() itself. But we're deviating from the topic of "async constructor", from which this is separate

# Dimitrian Nine (10 months ago)

"new MyObject() would return a promise "

I have one idea about it, but not sure good or not...

async class and then newAsync

Maybe this way more good for someone...

# T.J. Crowder (10 months ago)

On Sun, Feb 18, 2018 at 9:07 AM, Naveen Chawla <naveen.chwl at gmail.com>

wrote:

There is no rule that says you must propagate every promise.

I never said there was. I said you must handle rejection, or propagate the promise. Or, yes, you can ensure that the promise is never rejected, but that's not what the code I was responding to did. It left the door wide open to unhandled rejections.

-- T.J. Crowder

# kdex (10 months ago)

Having the constructor return a Promise is generally considered bad practice, since it breaks new X instanceof X, which in general breaks inheritance.

So, for this idea to work, you really shouldn't mark constructor as async (since this might suggest it returning a Promise, which it mustn't); instead, you would have to make the constructor return this, then make the asynchronous initialization, and then execute the rest. In other words,

something like this:

async class X {
	constructor() {
		await this.read();
		await this.write();
	}
	async read() { … }
	async write() { … }
}
console.log(new X());

would transpile like so:

class X {
	constructor() {}
	async initialize() {
		await this.read();
		await this.write();
	}
	async read() { … }
	async write() { … }
}
(new X()).initialize().then(x => {
	console.log(x);
});

The next problem with this idea is that you can't statically decide what new something is about to construct. Since something might be an async class, the StatementList following the construction of something would always have to be wrapped in a callback.

Long story short, introducing this feature would slow down new/ Reflect.construct.

# Dimitrian Nine (10 months ago)

"Long story short, introducing this feature would slow down new/ Reflect.construct" "since this might suggest it returning a Promise, which it mustn't "

Can it help: if async class constructor will be return Promise(obj) and i suggest before use newAsync for that practice?

Slow... but how much?

# Naveen Chawla (10 months ago)

I think awaitNew MyObject() would fit the thrust of your idea more. This would allow new MyObject() to still be an instance of the object instead of a promise, even if the constructor is async. It would dispatch the async parts of the constructor to the background instead of awaiting it. e.g.:

class MyObject {
    async constructor(){
        //sync stuff
        await doAsyncStuff();
        //etc.
    }
}

const
    myObjectWithOnlySyncStuffCompleted = new MyObject(), //Gets a new
instance but with only the "sync stuff" completed. Async stuff gets
dispatched to the background
    myObjectWithAsyncStuffCompleted = awaitNew MyObject() //Gets a new
instance with everything (including async stuff) completed
;

However, I have no problem the 1st version (new MyObject() returning a promise if the constructor is async). I think it's more consistent with how functions work anyway. But awaitNew serves the same requirement while ensuring new MyObject() is always an instance of MyObject.

# Dimitrian Nine (10 months ago)

"I think awaitNew MyObject() would fit the thrust of your idea more"

For me more good my first version... async class = return Promise(obj) But i can agree with others decisions, if in the end i get: easy way to async new

Some people ask me for some more interesting sample... Maybe it can help - try create:

//some module
async class FilterImg{
constructor(path,filters){
this.img = await load(path);
if (filters) {await this.use_filters(filters);}
}}
async use_filters(filters){
await filter1(this.image);
await filter2(this.image);
}}//class
export default FilterImg;
//end module

void async finction(){
let FilterImg = (await import(url)).default;
async class ExtFilterImg extends FilterImg{
constructor(path,filters){
await super(path);
if (filters) {await this.use_extFilters(filters);}
}}//class

let extFilter_img = await new FilterImg(path,filters);
console.log(extFilter_img.src+' '+extFilter_img.filters);
}();
# Isiah Meadows (10 months ago)

I'm still struggling through this thread to see why a static factory method/function with a private constructor/class doesn't suffice for this, or in this case, just procedural functions? (That's what I normally do, even in ES5.)

// filter-img.js
export async function create(path) {
    const img = await load(path)
    await filter1(img)
    await filter2(img)
    return img
}

// ext-filter-img.js
import * as FilterImg from "./filter-img.js"

async function create(path) {
    const img = await FilterImg.create(path)
    await extFilter1(img)
    await extFilter2(img)
    return img
}


(async () => {
    let ExtFilterImg = await import("./ext-filter-img.js")
    let extFilterImg = await ExtFilterImg.create(path)
    // ...
})()

Isiah Meadows me at isiahmeadows.com

Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com

# Dimitrian Nine (10 months ago)

"why a static factory"

I answered earlier: <<Maybe, but i think it question similiar to "factory vs class">>

Yes, you can, but for me more easy to work with classes. And i just want to extend the functionality for work with async - that all.

# Isiah Meadows (10 months ago)

I just thought I'd politely point out here that JS isn't a purely OO language (it's even less so class-based OO - ES classes are about 90% sugar over prototype-based inheritance*). Also, C#, the language that first had this kind of syntax, also doesn't have this. Constructors should be seen as what allocates and instantiates the instance, not what loads and creates the instance, and nearly every OO language out there assumes the former model, that of allocation/instantiation. (C++ is one of the unusual ones that conflates the two with its RAII.)

* There's a few features ES classes offer that prototypes don't, with new.target being the biggest one. But in general, ES classes aren't like traditional classes - they can be easily modified, up to and including their inheritance chain (which is downright trivial). Also, duck typing is reified in the spec, with that being used instead of interfaces when subclassing. Contrast this with Python, which makes it very difficult to change inheritance chains at runtime, and Ruby, which has had bugs over invalid assumptions with this (Classes don't invalidate their method caches with initialize_copy).


Isiah Meadows me at isiahmeadows.com

Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com

# Dimitrian Nine (10 months ago)

"ES classes are about 90% sugar" "ES classes aren't like traditional classes"

Yes and i just want to more sugar for them - just simple.

# Dimitrian Nine (10 months ago)

"why a static factory"

And more notes: "return img" - this is cut version of my example, you get image - not obj .

And my sample was simple. I hope not so long left to class private var + decorators

And sample can be then more complex with it:

async class Class{
@some_decorator
static private method(){}
static var = some_var
}

And have not only one Extends

Class
ExtClass
ExtExtClass

Maybe i try to force events, but time never waits...

# Dimitrian Nine (10 months ago)
class Test{
constructor(){}
async init(){}
static async newA(){
let obj = new Test(); obj.init(); return obj
}}
let t = Test.newA();

class ExtTest extends Test(){
constructor(){
super(); // we cant init here
//now we must recreate new/init for ExtTest too
}}

Or with my proposal we can easily do all async operation in constructor

async class Test{
constructor(){
}}
async class ExtTest extends Test(){
constructor(){
await super();
}}

Definition for async class = that async create and return Promise(obj)

# Dimitrian Nine (10 months ago)

«Classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript» «Classes are in fact "special functions"»

class = function Create(); 

all i want:

async class = async function Create();