Async Constructor

RMAG news

During a code review, I’ve been asked why I do not approve an object with an async constructor.

class Foo {
async constructor() {} // error
}

const f = await new Foo(); // WTF?!

The simple answer is that the language does not support it (Javascript in our case). But simple answers do not convince, so let’s find out why.

Take a look at the following example:

// async function that returns data after 1sec
function initSomeData() {
return new Promise(resolve => {
setTimeout(1000, () => resolve({foo: {bar: true}}))
})
}

class AsyncCtrIsBad {
data: {foo: {bar: boolean}};

constructor() {
// async code in our constructor
initSomeData().then(data => data = data);
}
}

const obj = new AsyncCtrIsBad();

console.log(obj.data.foo.bar); // <- the data does not exists yet

What do you think now about the async constructor?

Solution

Use async factory.

class AsyncCtrIsBad {
// the constructor do what it designed to do
// init object members
constructor(data: {foo: {bar: boolean}}) {
}
}

async function factory() {
const data = await initSomeData();
return new AsyncCtrIsBad(data);
}

const obj = await factory();

console.log(obj.data.foo.bar); // <- Works