简体   繁体   中英

Javascript async instantiation and private constructor

I need to instantiate an object asynchronously. But the constructor method cannot be declared async async constructor(){} and be called like so async new MyClass() . That would be strange anyway. Therefore, some kind of factory is needed. I also want to hide the constructor. This would be very easy to achieve if the constructor could be declared private: #constructor . But even with ES2022 private class features this is not possible. However, there are several patterns to solve these two problems. I will list 3 of them (in the context of ES6 modules).

I would like to know which pattern, if any, are considered good and which are not. Or if there are even better solutions, please let me know.

Method I: static boolean (without a factory)

let calledInit = false;

export default class MyClass {
    constructor(data) {
        if (calledInit === false)
            throw Error('private constructor');
        calledInit = false;
        // member initializations here
    }

    static async initialize() {
        calledInit = true;
        // do some async stuff here
        return new MyClass(data);
    }
}

Method II: closure and singleton-factory

const MyClass = (function() {
    class MyClass {
        constructor(data) {
            // member initializations here
        }
    }

    return {
        initialize: async function() {
            // do some async stuff here
            return new MyClass(data);
        }
    }    
})();
Object.freeze(MyClass);
export default MyClass;

use them both like so:

const obj = await MyClass.initialize();

Method III: factory function

class MyClass {
    constructor(data) {
        // member initializations here
    }
}

export default async function MyClassInitializer() {
    // do some async stuff here
    return new MyClass(data);
} 

use it like so:

const obj = await MyClassInitializer();

Edit: To clarify, I believe hiding the constructor is beneficial. Mainly for debugging purpose. Let's say the constructor is public and someone else is instantiating the object using the new operator. It always fails with obscure error messages and she/he can't make sense of it. All this, because she/he didn't carefully read the docs which clearly states to use the initialize() method to create an instance. This could easily have been prevented by hiding the constructor in the first place.

Disclaimer This is my opinion

Instantiating an object asynchronously is not really a thing for a good reason.

The purpose of the constructor is to construct your object. You should not put something like load operations from a file, API etc. in the constructor.

Put them into a separate function and use the result as an argument to your class.

async () => {
    const data = await fetch(...) // get data / do some sideeffect

    const myObject = new MyObject(data)
}

This is also usually desirable since you can update some state to track the progress of the request. Or you might want to cache it and use it in multiple places.

async () => {

    state = "LOADING"
    const data = await fetch(...) // get data / do some sideeffect

    state = "SUCCESS"

    const myObject = new MyObject(data)
}

Hiding the constructor is not really needed since you get an error when you do not pass data to it. And the user of your class should know what to pass. If you use typescript, this would be even more strict.

Sure you can put this in one initialize function as in method 3.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM