【问题标题】:Creating an async singletone in javascript在 javascript 中创建异步单例
【发布时间】:2020-01-06 12:23:41
【问题描述】:

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

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;
    }
}

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

【问题讨论】:

  • 我没有看到任何理由,如果承诺被正确拒绝,它应该可以工作。我们也可以检查someAsyncFunction吗?
  • @sjahan 即使 promise 被拒绝,asyncCompInstance 也不再为 null,因此 getAsyncCompInstance() 会返回它而不是继续调用 createAsyncInstance() 的下一行
  • 如果someAsyncFunction 抛出错误,则不会执行下一行,因此不会返回任何实例。您可以在静态方法中放置一个 try catch 并在出现错误时返回 null。
  • @AshishModi,这不准确。 getAsyncCompInstance() 不会等待 createAsyncInstance(),它会立即返回 Promise。调用 getAsyncCompInstance() 的代码负责错误处理,如果 getAsyncCompInstance() 抛出/拒绝,此代码将捕获它。
  • 我的错。完全错过了“不等待”的部分。

标签: javascript node.js asynchronous async-await singleton


【解决方案1】:

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

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;
    }
}

我知道这不是最干净的代码,尤其不是经典的工厂模式实现,但这是我目前能想到的最好的。很想听听有关此解决方案的 cmets/建议。

【讨论】:

  • 该方法很好(类似于what I would do),但为了清洁,我会将try/catch 移动到getAsyncCompInstance 方法中,该方法的作用是存储单例。或者真的只是将它们合并到一个方法中,因为你永远不想单独调用createAsyncInstance(忽略单例)。
  • 进一步的重构可能会将new AsyncComp 调用移到try 块之外——您只想处理来自someAsyncFunction 的错误,但由于构造函数失败而重试可能毫无意义。继续这一点,您可以将重试逻辑移动到someAsyncFunction 中,并将最终拒绝作为最终值。但这很大程度上取决于您的使用场景,如果有多个getAsyncCompInstance() 的调用站点,并且您认为共享它们的错误处理不够灵活,那么您最好完全避免使用单例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-19
  • 1970-01-01
  • 2014-05-08
  • 2020-04-24
  • 1970-01-01
相关资源
最近更新 更多