在JavaScript中创建一个异步单例

huangapple go评论153阅读模式
英文:

Creating an async singletone in javascript

问题

我需要实现一个异步单例,该单例创建一个需要异步操作来传递参数给构造函数的类的单个实例。
我有以下代码:

class AsyncComp {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    // 用于创建异步实例的工厂方法
    static async createAsyncInstance() {
        const info = await someAsyncFunction();
        return new AsyncComp(info.x, info.y);
    }

    // 单例方法
    static getAsyncCompInstance() {
        if (asyncCompInstance) return asyncCompInstance;
        asyncCompInstance = AsyncComp.createAsyncInstance();
        return asyncCompInstance;
    }
}

代码似乎正常工作,只要 Promise 得以完成。但是,如果 Promise 被拒绝,下一次调用 getAsyncCompInstance() 将返回未完成的 Promise 对象,这意味着无法重试创建对象。
我该如何解决这个问题?

英文:

I need to implement an async singleton, that creates a single instance of a class that requires asynchronous operations in order to pass arguments to the constructor.
I have the following code:

class AsyncComp {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    // A factory method for creating the async instance
    static async createAsyncInstance() {
        const info = await someAsyncFunction();
        return new AsyncComp(info.x, info.y);
    }

    // The singleton method
    static getAsyncCompInstance() {
        if (asyncCompInstance) return asyncCompInstance;
        asyncCompInstance = AsyncComp.createAsyncInstance();
        return asyncCompInstance;
    }
}

The code seems to work fine, as long as the promise fulfils. If, however, the promise is rejected the next calls to getAsyncCompInstance() will return the unfulfilled promise object, which means that it will not be possible to retry the creation of the object.
How can I solve this?

答案1

得分: 1

经过考虑了几种可能的解决方案后,我决定在 createAsyncInstance() 中用 try/catch 块包装异步调用,并且如果失败,将 asyncCompInstance 设置为 null,并抛出发生的错误。这样,如果对象创建失败,调用者可以再次调用 getAsyncCompInstance() 尝试获取类的实例:

class AsyncComp {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    // 用于创建异步实例的工厂方法
    static async createAsyncInstance() {
        try {
            const info = await someAsyncFunction();
            return new AsyncComp(info.x, info.y);
        }
        catch (err) {
            asyncCompInstance = null;
            throw err;
        }
    }

    // 单例方法
    static getAsyncCompInstance() {
        if (asyncCompInstance) return asyncCompInstance;
        asyncCompInstance = AsyncComp.createAsyncInstance();
        return asyncCompInstance;
    }
}

我知道这不是最干净的代码,特别是不是经典的工厂模式实现,但这是我目前能想到的最好的解决方案。希望听到对这个解决方案的评论/建议。

英文:

So after thinking about a couple of possible solution, I decided to wrap the asynchronous call in createAsyncInstance() with a try/catch block, and if it failed, set asyncCompInstance back to be null, and throw the error the occurred. This way, if the object creation failed, the caller can call getAsyncCompInstance() again to try to get an instance of the class:

class AsyncComp {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    // A factory method for creating the async instance
    static async createAsyncInstance() {
        try {
            const info = await someAsyncFunction();
            return new AsyncComp(info.x, info.y);
        }
        catch (err) {
            asyncCompInstance = null;
            throw err;
        }
    }

    // The singleton method
    static getAsyncCompInstance() {
        if (asyncCompInstance) return asyncCompInstance;
        asyncCompInstance = AsyncComp.createAsyncInstance();
        return asyncCompInstance;
    }
}

I know this is not the cleanest code, and specifically not the classic factory pattern implementation, but this is the best I could come up with at the moment. Would love to hear comments/suggestions on this solution.

huangapple
  • 本文由 发表于 2020年1月6日 20:23:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/59612076.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定