Async Class
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
"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...
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
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
"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)
]);
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.
"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...
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).
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
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.
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
"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...
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
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
.
"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?
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
.
"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);
}();
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
"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.
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
"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.
"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...
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)
«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();
Ok so much time has passed. I have learned more js. And created some wrapper for my idea:
Class is just function constructor that return object. Async Class is async function constructor that returns promise object. Wrapper code:
class PromiseClass { //promisified class
static async new(obj){ return obj;}
constructor() {return PromiseClass.new(this); }//new
}//class
class AsyncClass extends PromiseClass{ // can ext Class|PromiseClass
static async new(obj){return await obj();}
constructor(){return AsyncClass.new(async()=>{await super(); return this});}//new
}//AsyncClass
And we work with Async Class like we work with functions. I dont see here some differents to use them. Code without wrapper be clean:
async class PromiseClass { //return Promise
constructor() {}//async()=>Promise object
}//class
async class AsyncClass extends PromiseClass{ // can ext Class|PromiseClass
constructor(){ await super();} //async()=>Promise object
}//AsyncClass
Not a bad idea, but I'd strongly prefer the promise to be returned
from new AsyncClass(...)
itself instead. And down that vein, super
with async classes should also implicitly await
in its super
call,
setting this
to the value itself. For sanity reasons, super
should
return a promise resolved with the set this
, so you can still use it
and await it in inner arrow functions (it's possible), but it should
still do its own implicit awaiting, just so you can add properties to
the right instance. (This will also come into play with private
properties - you want those on the instance, not the promise.)
I do have a preference: async
should decorate the constructor
, not
the class
. It's not the class that's async, it's the constructor
itself. You can still have sync methods elsewhere in the class, and
this doesn't do anything to affect that, hence why I'd prefer an
async constructor(...) { ... }
instead of an async class
.
Isiah Meadows contact at isiahmeadows.com, www.isiahmeadows.com
Not a bad idea, but I'd strongly prefer the promise to be returned from new AsyncClass(...) itself instead
This about wrapper? He is just example of how functional can work right now.
I do have a preference: async should decorate the constructor, not the class
How i say before: both variants fine for me. But how discussed here - not all think same. For me Class is just wrapper on constructor. And Async Class is same only for async constructor.
How it says: "there is no limit to perfection" - new wrapper. Now it works like more native:
class PromiseClass {
static async new(test='test'){ this.promise= test; return this;}
constructor(...args) {
let s = async()=>PromiseClass.new.call(this,...args);
return (async r=>await s() )();
}//new
}//class
class AsyncClass extends PromiseClass{
static async new(){ return this; }
constructor(...args){
let s = async()=>{ await super(); return AsyncClass.new.call(this,...args); };
return (async r=>await s() )();
}//new
}//AsyncClass
Le 26 août 2019 à 17:11, Dimitrian Nine <dimtimeforever at gmail.com> a écrit :
Class is just function constructor that return object
Although in JS a class is represented by the same object as its constructor, I don’t think it is good to assimilate the concept of JS class and JS constructor. Indeed, a class consists not only of its constructor, but also of all its associated methods. This is what is suggested by the syntax:
class C {
/* definition of all methods, not only constructor */
}
From that perspective, I understand very well what would be an “async constructor”; but an “async class” doesn’t make much sense.
class-factories are good enough. as real-world example, google-puppeteer uses class-factories to promisify its constructors, which are easy-to-reason.
if the below Browser/Page classes were also "async", it would be difficult to debug their intent in real-world code -- are their instances supposed to act as promises or as data-objects? i imagine code-maintennance would be a nightmare.
// "await" puppeteer's Browser constructor
// https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/lib/Browser.js#L23
class Browser extends EventEmitter {
constructor(connection, contextIds, ...) {
...
}
static async create(connection, contextIds, ...) {
const browser = new Browser(connection, contextIds, ...);
await connection.send(...);
return browser;
}
}
//
https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/lib/Launcher.js#L184
const browser = await Browser.create(connection, [], ...);
// "await" puppeteer's Page constructor
// https://github.com/GoogleChrome/puppeteer/blob/v1.19.0/lib/Page.js#L36
class Page extends EventEmitter {
constructor(client, target, ...) {
...
}
static async create(client, target, ...) {
const page = new Page(client, target, ...);
await page._initialize();
...
return page;
}
}
//
https://github.com/kaizhu256/puppeteer-to-istanbul-example/blob/6b3f599f/screenshot.js#L317
page1 = await module.exports.Page.create(null, tmp);
Claude Pache
class consists not only of its constructor
How i see it - seems all think that my idea not bad, but we have semantic hell. My thougth was Class is wrapper for constructor Object. And Async Class is same wrapper for constructor Promise of Object
kai zhu
class-factories are good enough
For all? Not for me - i want more clean and native methods.
if the below Browser/Page classes were also "async"
And way you described - try to Extends Browser Class. How you do that? I think my wrapper more easy and simple. .......................................................................
Sorry i am not philosopher and how it be named not strong interesting me. I need functionality and how i saw not only for me. just maybe start think about how it resolved? Maybe use another name - not async, but promise_class for example? Class => Obj, PromiseClass => Promise of Obj
Update: now we have proposal 1 stage
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(); }}