At the second, I’m making an attempt to make use of async/await
inside a category constructor operate. This is in order that I can get a customized e-mail
tag for an Electron venture I’m engaged on.
customElements.outline('e-mail', class extends HTMLElement {
async constructor() {
tremendous()
let uid = this.getAttribute('data-uid')
let message = await grabUID(uid)
const shadowRoot = this.attachShadow({mode: 'open'})
shadowRoot.innerHTML = `
<div id="email">A random e-mail message has appeared. ${message}</div>
`
}
})
At the second nonetheless, the venture doesn’t work, with the next error:
Class constructor might not be an async technique
Is there a solution to circumvent this in order that I can use async/await inside this? Instead of requiring callbacks or .then()?
,
This can by no means work.
The async
key phrase permits await
for use in a operate marked as async
nevertheless it additionally converts that operate right into a promise generator. So a operate marked with async
will return a promise. A constructor then again returns the article it’s setting up. Thus we’ve got a state of affairs the place you wish to each return an object and a promise: an unimaginable state of affairs.
You can solely use async/await the place you need to use guarantees as a result of they’re basically syntax sugar for guarantees. You can’t use guarantees in a constructor as a result of a constructor should return the article to be constructed, not a promise.
There are two design patterns to beat this, each invented earlier than guarantees had been round.
- Use of an
init()
operate. This works a bit like jQuery’s .prepared()
. The object you create can solely be used inside its personal init
or prepared
operate:
Usage:
var myObj = new myClass();
myObj.init(operate() {
// inside right here you need to use myObj
});
Implementation:
class myClass {
constructor () {
}
init (callback) {
// do one thing async and name the callback:
callback.bind(this)();
}
}
- Use a builder. I’ve not seen this used a lot in javascript however this is likely one of the extra frequent work-arounds in Java when an object must be constructed asynchronously. Of course, the builder sample is used when setting up an object that requires plenty of sophisticated parameters. Which is strictly the use-case for asynchronous builders. The distinction is that an async builder doesn’t return an object however a promise of that object:
Usage:
myClass.construct().then(operate(myObj) {
// myObj is returned by the promise,
// not by the constructor
// or builder
});
// with async/await:
async operate foo () {
var myObj = await myClass.construct();
}
Implementation:
class myClass {
constructor (async_param) {
if (typeof async_param === 'undefined') {
throw new Error('Cannot be referred to as straight');
}
}
static construct () {
return doSomeAsyncStuff()
.then(operate(async_result){
return new myClass(async_result);
});
}
}
Implementation with async/await:
class myClass {
constructor (async_param) {
if (typeof async_param === 'undefined') {
throw new Error('Cannot be referred to as straight');
}
}
static async construct () {
var async_result = await doSomeAsyncStuff();
return new myClass(async_result);
}
}
Note: though within the examples above we use guarantees for the async builder they don’t seem to be strictly talking mandatory. You can simply as simply write a builder that settle for a callback.
Note on calling capabilities inside static capabilities.
This has nothing in any respect to do with async constructors however with what the key phrase this
really imply (which can be a bit stunning to folks coming from languages that do auto-resolution of technique names, that’s, languages that don’t want the this
key phrase).
The this
key phrase refers back to the instantiated object. Not the category. Therefore you can’t usually use this
inside static capabilities for the reason that static operate is just not sure to any object however is sure on to the category.
That is to say, within the following code:
class A {
static foo () {}
}
You can’t do:
var a = new A();
a.foo() // NOPE!!
as an alternative it’s essential to name it as:
A.foo();
Therefore, the next code would end in an error:
class A {
static foo () {
this.bar(); // you're calling this as static
// so bar is undefinned
}
bar () {}
}
To repair it you can also make bar
both a daily operate or a static technique:
operate bar1 () {}
class A {
static foo () {
bar1(); // that is OK
A.bar2(); // that is OK
}
static bar2 () {}
}
,
You can positively do that, by returning an Immediately Invoked Async Function Expression from the constructor. IIAFE
is the flowery title for a quite common sample that was required with the intention to use await
exterior of an async operate, earlier than top-level await turned out there:
(async () => {
await someFunction();
})();
We’ll be utilizing this sample to instantly execute the async operate within the constructor, and return its end result as this
:
// Sample async operate for use within the async constructor
async operate sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
class AsyncConstructor {
constructor(worth) {
return (async () => {
// Call async capabilities right here
await sleep(500);
this.worth = worth;
// Constructors return `this` implicitly, however that is an IIFE, so
// return `this` explicitly (else we would return an empty object).
return this;
})();
}
}
(async () => {
console.log('Constructing...');
const obj = await new AsyncConstructor(123);
console.log('Done:', obj);
})();
To instantiate the category, use:
const occasion = await new AsyncConstructor(...);
For TypeScript, it’s essential to assert that the kind of the constructor is the category kind, quite than a promise returning the category kind:
class AsyncConstructor {
constructor(worth) {
return (async (): Promise<AsyncConstructor> => {
// ...
return this;
})() as unknown as AsyncConstructor; // <-- kind assertion
}
}
- Extending a category with an async constructor could have a limitation. If it’s essential to name
tremendous
within the constructor of the derived class, you’ll should name it with out await
. If it’s essential to name the tremendous constructor with await
, you’ll run into TypeScript error 2337: Super calls should not permitted exterior constructors or in nested capabilities inside constructors.
- It’s been argued that it’s a “bad practice” to have a constructor function return a Promise.
Before utilizing this answer, decide whether or not you’ll want to increase the category, and doc that the constructor should be referred to as with await
.
,
Because async capabilities are guarantees, you possibly can create a static operate in your class which executes an async operate which returns the occasion of the category:
class Yql {
constructor () {
// Set up your class
}
static init () {
return (async operate () {
let yql = new Yql()
// Do async stuff
await yql.construct()
// Return occasion
return yql
}())
}
async construct () {
// Do stuff with await if wanted
}
}
async operate yql () {
// Do this as an alternative of "new Yql()"
let yql = await Yql.init()
// Do stuff with yql occasion
}
yql()
Call with let yql = await Yql.init()
from an async operate.
,
Unlike others have stated, you may get it to work.
JavaScript class
es can return actually something from their constructor
, even an occasion of one other class. So, you would possibly return a Promise
from the constructor of your class that resolves to its precise occasion.
Below is an instance:
export class Foo {
constructor() {
return (async () => {
// await something you need
return this; // Return the newly-created occasion
})();
}
}
Then, you’ll create situations of Foo
this fashion:
const foo = await new Foo();
,
The stopgap answer
You can create an async init() {... return this;}
technique, then as an alternative do new MyClass().init()
everytime you’d usually simply say new MyClass()
.
This is just not clear as a result of it depends on everybody who makes use of your code, and your self, to all the time instantiate the article like so. However for those who’re solely utilizing this object in a selected place or two in your code, it might possibly be nice.
A major drawback although happens as a result of ES has no kind system, so for those who overlook to name it, you’ve simply returned undefined
as a result of the constructor returns nothing. Oops. Much higher could be to do one thing like:
The neatest thing to do could be:
class AsyncSolelyObject {
constructor() {
}
async init() {
this.someField = await this.calculateStuff();
}
async calculateStuff() {
return 5;
}
}
async operate newAsync_AsyncSolelyObject() {
return await new AsyncSolelyObject().init();
}
newAsync_AsyncSolelyObject().then(console.log);
// output: AsyncSolelyObject {someField: 5}
The manufacturing unit technique answer (barely higher)
However then you definately would possibly by chance do new AsyncSolelyObject, it’s best to most likely simply create manufacturing unit operate that makes use of Object.create(AsyncOnlyObject.prototype)
straight:
async operate newAsync_AsyncSolelyObject() {
return await Object.create(AsyncSolelyObject.prototype).init();
}
newAsync_AsyncSolelyObject().then(console.log);
// output: AsyncSolelyObject {someField: 5}
However say you wish to use this sample on many objects… you may summary this as a decorator or one thing you (verbosely, ugh) name after defining like postProcess_makeAsyncInit(AsyncSolelyObject)
, however right here I’m going to make use of extends
as a result of it type of suits into subclass semantics (subclasses are mum or dad class + further, in that they need to obey the design contract of the mum or dad class, and should do further issues; an async subclass could be unusual if the mum or dad wasn’t additionally async, as a result of it couldn’t be initialized the identical method):
Abstracted answer (extends/subclass model)
class AsyncObject {
constructor() {
throw new Error('lessons descended from AsyncObject should be initialized as (await) TheClassTitle.anew(), quite than new TheClassTitle()');
}
static async anew(...args) {
var R = Object.create(this.prototype);
R.init(...args);
return R;
}
}
class MyObject extends AsyncObject {
async init(x, y=5) {
this.x = x;
this.y = y;
// bonus: we want not return 'this'
}
}
MyObject.anew('x').then(console.log);
// output: MyObject {x: "x", y: 5}
(don’t use in manufacturing: I’ve not thought by sophisticated eventualities equivalent to whether or not that is the correct solution to write a wrapper for key phrase arguments.)
,
Based in your feedback, it’s best to most likely do what each different HTMLElement with asset loading does: make the constructor begin a sideloading motion, producing a load or error occasion relying on the end result.
Yes, meaning utilizing guarantees, nevertheless it additionally means “doing things the same way as every other HTML element”, so that you’re in good firm. For occasion:
var img = new Image();
img.onload = operate(evt) { ... }
img.addEventListener("load", evt => ... );
img.onerror = operate(evt) { ... }
img.addEventListener("error", evt => ... );
img.src = "https://codeutility.org/2023/02/10/javascript-async-await-class-constructor-code-utility/some url";
this kicks off an asynchronous load of the supply asset that, when it succeeds, ends in onload
and when it goes improper, ends in onerror
. So, make your personal class do that too:
class EMailElement extends HTMLElement {
relatedCallagain() {
this.uid = this.getAttribute('data-uid');
}
setAttribute(title, worth) {
tremendous.setAttribute(title, worth);
if (title === 'data-uid') {
this.uid = worth;
}
}
set uid(enter) {
if (!enter) return;
const uid = parseInt(enter);
// do not battle the river, drift, use a promise:
new Promise((resolve, reject) => {
yourDataBase.getByUID(uid, (err, end result) => {
if (err) return reject(err);
resolve(end result);
});
})
.then(end result => {
this.renderLoaded(end result.message);
})
.catch(error => {
this.renderError(error);
});
}
};
customElements.outline('e-mail', EmailElement);
And then you definately make the renderLoaded/renderError capabilities take care of the occasion calls and shadow dom:
renderLoaded(message) {
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<div class="email">A random e-mail message has appeared. ${message}</div>
`;
// is there an historical occasion listener?
if (this.onload) {
this.onload(...);
}
// there may be trendy occasion listeners. dispatch an occasion.
this.dispatchEvent(new Event('load'));
}
renderFailed() {
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<div class="email">No e-mail messages.</div>
`;
// is there an historical occasion listener?
if (this.onload) {
this.onerror(...);
}
// there may be trendy occasion listeners. dispatch an occasion.
this.dispatchEvent(new Event('error'));
}
Also be aware I modified your id
to a class
, as a result of except you write some bizarre code to solely ever enable a single occasion of your <e-mail>
ingredient on a web page, you possibly can’t use a novel identifier after which assign it to a bunch of parts.
,
I often desire a static async technique that returns a brand new occasion, however right here’s one other solution to do it. It’s nearer to actually awaiting a constructor. It works with TypeScript.
class Foo {
#promiseReady;
constructor() {
this.#promiseReady = this.#init();
}
async #init() {
await someAsyncStuff();
return this;
}
prepared() {
return this.promiseReady;
}
}
let foo = await new Foo().prepared();
,
I made this test-case based mostly on @Downgoat’s reply.
It runs on NodeJS.
This is Downgoat’s code the place the async half is offered by a setTimeout()
name.
'use strict';
const util = require( 'util' );
class AsyncConstructor{
constructor( lapse ){
this.qqq = 'QQQ';
this.lapse = lapse;
return ( async ( lapse ) => {
await this.delay( lapse );
return this;
})( lapse );
}
async delay(ms) {
return await new Promise(resolve => setTimeout(resolve, ms));
}
}
let run = async ( millis ) => {
// Instatiate with await, inside an async operate
let asyncConstructed = await new AsyncConstructor( millis );
console.log( 'AsyncConstructor: ' + util.examine( asyncConstructed ));
};
run( 777 );
My use case is DAOs for the server-side of an online software.
As I see DAOs, they’re each related to a document format, in my case a MongoDB assortment like as an example a cook dinner.
A cooksDAO occasion holds a cook dinner’s knowledge.
In my stressed thoughts I’d have the ability to instantiate a cook dinner’s DAO offering the cookId as an argument, and the instantiation would create the article and populate it with the cook dinner’s knowledge.
Thus the necessity to run async stuff into the constructor.
I needed to jot down:
let cook dinner = new cooksDAO( '12345' );
to have out there properties like cook dinner.getDisplayName()
.
With this answer I’ve to do:
let cook dinner = await new cooksDAO( '12345' );
which is similar to the best.
Also, I would like to do that inside an async
operate.
My B-plan was to go away the information loading out of the constructor, based mostly on @slebetman suggestion to make use of an init operate, and do one thing like this:
let cook dinner = new cooksDAO( '12345' );
async cook dinner.getData();
which doesn’t break the principles.
,
Use the async technique in constructor???
constructor(props) {
tremendous(props);
(async () => await this.qwe(() => console.log(props), () => console.log(props)))();
}
async qwe(q, w) {
return new Promise((rs, rj) => {
rs(q());
rj(w());
});
}
,
If you possibly can keep away from prolong
, you possibly can keep away from lessons all collectively and use operate composition as constructors. You can use the variables within the scope as an alternative of sophistication members:
async operate buildA(...) {
const knowledge = await fetch(...);
return {
getData: operate() {
return knowledge;
}
}
}
and easy use it as
const a = await buildA(...);
If you’re utilizing typescript or move, you possibly can even implement the interface of the constructors
Interface A {
getData: object;
}
async operate buildA0(...): Promise<A> { ... }
async operate buildA1(...): Promise<A> { ... }
...
,
I discovered myself in a state of affairs like this and ended up utilizing an IIFE
// utilizing TypeScript
class SomeClass {
constructor() {
// do one thing right here
}
doSomethingAsync(): SomeClass {
(async () => await asyncTask())();
return this;
}
}
const someClass = new SomeClass().doSomethingAsync();
If you will have different duties which can be dependant on the async job you possibly can run them after the IIFE completes its execution.
,
Quite a lot of nice data right here and a few tremendous() considerate responses. In brief the method outlined under is pretty easy, non-recursive, async-compatible and performs by the principles. More importantly I don’t consider it has been correctly lined right here but – although please right me if improper!
Instead of technique calls we merely assign an II(A)FE to an occasion prop:
// it is async-lite!
class AsyncLiteComponent {
constructor() {
// our occasion features a 'prepared' property: an IIAFE promise
// that auto-runs our async wants after which resolves to the occasion
// ...
// that is the first distinction to different solutions, in that we defer
// from a property, not a way, and the async performance each
// auto-runs and the promise/prop resolves to the occasion
this.prepared = (async () => {
// on this instance we're auto-fetching one thing
this.msg = await AsyncLiteComponent.msg;
// we return our occasion to permit nifty one-liners (see under)
return this;
})();
}
// we hold our async performance in a static async getter
// ... technically (with some minor tweaks), we might prefetch
// or cache this response (however that is not actually our purpose right here)
static get msg() {
// sure I do know - this instance returns virtually instantly (creativeness folks!)
return fetch('knowledge:,Hello%20Worldpercent21').then((e) => e.textual content());
}
}
Seems easy sufficient, how is it used?
// Ok, so that you *might* instantiate it the conventional, excessively boring method
const iwillnotwait = new AsyncLiteComponent();
// and defer your ready for later
await iwillnotwait.prepared
console.log(iwillnotwait.msg)
// OR OR OR you may get all async/awaity about it!
const onlywhenimready = await new AsyncLiteComponent().prepared;
console.log(onlywhenimready.msg)
// ... for those who're actually antsy you may even "pre-wait" utilizing the static technique,
// however you'd most likely need some caching / replace logic within the class first
const prefetched = await AsyncLiteComponent.msg;
// ... and I have never totally examined this nevertheless it must also be open for extension
class Extensior extends AsyncLiteComponent {
constructor() {
tremendous();
this.prepared.then(() => console.log(this.msg))
}
}
const extendedwaittime = await new Extensior().prepared;
Before posting I had a quick dialogue on the viability of this method in the comments of @slebetman’s comprehensive answer. I wasn’t fully satisfied by the outright dismissal, so thought I’d open it as much as additional debate / tear down. Please do your worst 🙂
,
You can use Proxy’s assemble
deal with to do that, the code like this:
const SomeClass = new Proxy(class A {
constructor(person) {
this.person = person;
}
}, {
async assemble(goal, args, newTarget) {
const title = args;
// you need to use await in right here
const person = await fetch(title);
// invoke new A right here
return new goal(person);
}
});
const a = await new SomeClass('cage');
console.log(a.person); // person information
,
Variation on the builder sample, utilizing name():
operate asyncMethod(arg) {
operate internalPromise() { return new Promise((...)=> {...}) }
internalPromise().then(end result => {
this.setStuff(end result);
}
}
const getInstance = async (arg) => {
let occasion = new Instance();
await asyncMethod.name(occasion, arg);
return occasion;
}
,
That might be completed.
A easy code:
class take a look at
{
constructor ()
{
return new Promise ( (resolve, reject) => { resolve(this); });
}
doHello() {console.log("hello");}
}
async operate foremost()
{
let t = await new take a look at(); //invoking synchronously
t.doHello(); //t is just not a pormise
}
foremost();
Or similar as above however with actual delays added, with setTimeout
class take a look at
{
constructor ()
{
return new Promise ( (resolve, reject) =>
{
setTimeout (resolve, 5, this);
});
}
doHello() {console.log("hello");}
}
async operate foremost()
{
let t = new take a look at(); //now t is a promise
t.then((a)=>{ a.doHello();}); //a is the true reference to check occasion
console.log("testing"); //"testing" can be printed 5 seconds earlier than "hello"
}
foremost();
And right here a bit from my code in actual life, with async picture loading:
class HeightMap extends GlVAObject
{
#vertices = ;
constructor (src, crossOrigin = "")
{
//tremendous(theContextSetup);
let picture = new Image();
picture.src = src;
picture.crossOrigin = crossOrigin;
return new Promise ( (resolve, reject) =>
{
picture.addEventListener('load', () =>
{
//studying pixel values from picture into this.#vertices
//and generate a heights map
//...
resolve(this);
} );
});
}
///...
}
async operate foremost()
{
let vao = await new HeightMap ("./heightmaps/ArisonaCraterHeightMap.png");
///...
}
foremost();
,
You could instantly invoke an nameless async operate that returns message and set it to the message variable. You would possibly need to check out instantly invoked operate expressions (IEFES), in case you’re unfamiliar with this sample. This will work like a attraction.
var message = (async operate() { return await grabUID(uid) })()
,
You ought to add then
operate to occasion. Promise
will acknowledge it as a thenable object with Promise.resolve
routinely
const asyncSymbol = Symbol();
class MyClass {
constructor() {
this.asyncData = null
}
then(resolve, reject) {
return (thisasyncSymbol = thisasyncSymbol || new Promise((innerResolve, innerReject) => {
this.asyncData = { a: 1 }
setTimeout(() => innerResolve(this.asyncData), 3000)
})).then(resolve, reject)
}
}
async operate wait() {
const asyncData = await new MyClass();
alert('run 3s later')
alert(asyncData.a)
}
,
@slebetmen’s accepted reply explains effectively why this doesn’t work. In addition to the 2 patterns introduced in that reply, an alternative choice is to solely entry your async properties by a customized async getter. The constructor() can then set off the async creation of the properties, however the getter then checks to see if the property is accessible earlier than it makes use of or returns it.
This strategy is especially helpful while you wish to initialize a worldwide object as soon as on startup, and also you wish to do it inside a module. Instead of initializing in your index.js
and passing the occasion within the locations that want it, merely require
your module wherever the worldwide object is required.
Usage
const occasion = new MyClass();
const prop = await occasion.getMyProperty();
Implementation
class MyClass {
constructor() {
this.myProperty = null;
this.myPropertyPromise = this.obtainAsyncStuff();
}
async obtainAsyncStuff() {
// await yourAsyncCall();
this.myProperty = 'async property'; // this is able to as an alternative by your async name
return this.myProperty;
}
getMyProperty() {
if (this.myProperty) {
return this.myProperty;
} else {
return this.myPropertyPromise;
}
}
}
,
The closest you may get to an asynchronous constructor is by ready for it to complete executing if it hasn’t already in all of its strategies:
class SomeClass {
constructor() {
this.asyncConstructor = (async () => {
// Perform asynchronous operations right here
})()
}
async someMethod() {
await this.asyncConstructor
// Perform regular logic right here
}
}
,
The different solutions are lacking the apparent. Simply name an async operate out of your constructor:
constructor() {
setContentAsync();
}
async setContentAsync() {
let uid = this.getAttribute('data-uid')
let message = await grabUID(uid)
const shadowRoot = this.attachShadow({mode: 'open'})
shadowRoot.innerHTML = `
<div id="email">A random e-mail message has appeared. ${message}</div>
`
}