- Stage: 1
- Champion: Bradley Farias (GoDaddy)
Class features are unable to properly integrate with some async workflows in JS. This proposal seeks to aid async initialization of class instances.
As stage 1, the current effort is into finding which design would be appealing given our goals.
- Encapsulate incomplete initialization
- Allow a reasonable subclass workflow
Mark an entire class as async
as well as the constructor
:
async class Query {
async constructor() {
this.data = await performQuery('select * from table;');
}
}
This is somewhat nice as it does open a path towards await
during field
initialization:
const connection = db.connect();
async class Table {
db = await connection;
query(q) {
return db.query(q);
}
}
Only make constructor
marked as async
.
class Query {
async constructor() {
await performQuery('select * from table;')
}
}
This is minimal, but due to timing concerns.
class Query {
#constructor(data) {
this.data = data;
}
async create() {
return new Query.prototype.#constructor(
await performQuery('select * from table;')
);
}
}
This is also somewhat minimal, but does not allow for subclasses to easily extend the initialization since it is private.
All the solutions face some level of commonality for problems:
await super()
is already valid so a new syntax would be needed in order to
differentiate how this
should be assigned. For bike shed mitigation, I will
be using await.super()
as a placeholder for now. It cannot be placed as a
meta-property on super
because super.*
is also already valid syntax.
Considering that many classes can perform meaningful actions prior to accessing superclass initialized behavior, it should be possible to queue such actions.
What other languages support await
during construction and encapsulate the instance until construction finishes?
None found so far, but will happily document any. Lots of languages have various patterns for dealing with this problem space though. It seems somewhat common to have the following:
class Instance {}
async function instanceFactory() {
// awaits go here
f(new Instance(data));
}
Unclear, but it seems that abstract classes would need to know timing.
Timing is needed to avoid races such as performing an action too early and
async
initialization may affect the timing by which subclass super
resumes.
This leans towards banning mixing of async
& non-async
initialization to
some extent. It seems unsafe for a non-async
initialization to subclass an
async initialization, but the opposite has not yet seen a problem.