实现getOrCreate方法异步问题

时间:2018-02-05 11:02:43

标签: javascript asynchronous promise

我有一个封装与服务器通信的类 它有一个getOrCreate方法在服务器中创建一个ShoppingCart资源(我使用的是firebase,但我的问题是所有类型的服务器实现)

一旦应用程序加载到客户端(我正在使用角度,但这对于这个问题无关紧要),两个不同的组件(屏幕区域)获取注入它们的服务类(它是单例)和他们调用方法getOrCreateCart() 如果存在cartId,则此方法应检查localStorage,如果存在,则返回它。否则,它应该通过对服务器的异步调用来创建它。 问题是,如果两个组件同时调用此方法,缺少锁定机制,我不能阻止第二个操作,直到第一个操作完成,第二个时间从localStrogate返回cartId而不是创建另一个数据库中的资源

检查数据库中是否已存在cartId不是一个选项,因为cartId是在请求服务器时生成的。

一些代码可以使事情变得更加清晰:

private async getOrCreateCartId() {
    let cartId = localStorage.getItem('cartId');
    if (cartId) return cartId;

    let newCartId = await this.create();
    localStorage.setItem('cartId', newCartId);
    return newCartId;
  }

 // Returns a promise with the new created id
 private create() {
    return this.db.list('/shopping-carts/').push({
      dateCreated: new Date().getTime()
    });
  }

2 个答案:

答案 0 :(得分:1)

感谢Roamer-1888,我已经明白了

这是我的解决方案:

  1. 缓存从create()方法返回的承诺
  2. 对于所有后续调用,返回此承诺,以便当结果从服务器到达时,将调用所有返回的承诺
  3. 在返回承诺之前,我调用然后将服务器中的值转换为我感兴趣的简单字符串。
  4. 我最终得到了这段代码:

    private getOrCreateCartId() {
        let cartId = localStorage.getItem('cartId');
        if (cartId) return Promise.resolve(cartId);
    
        if (this.createPromise) return this.createPromise.then(result => result.key);
    
        this.createPromise = this.create();
        this.createPromise.then(result => {
          localStorage.setItem('cartId', result.key);
        })
        return this.createPromise.then(result => result.key);
      }
    

答案 1 :(得分:0)

恭喜你搞清楚了。

这是我最终的结果,首先是模拟你的单身人士:

// singleton FOO
const FOO = (function() {
    var cartId = localStorage.getItem('cartId'); // cache, initialised from localStorage

    async function getOrCreateCartId() {
        if (!cartId) {
            cartId = create(); // cache promise
            localStorage.setItem('cartId', await cartId);
        }
        return cartId;
    }

    // Returns a promise with the new created id
    function create() {
        return new Promise(function(resolve, reject) {
            setTimeout(() => {
                resolve(Date.now());
            }, 2000);
        });
    }
    return {
        'getOrCreateCartId': getOrCreateCartId
    };
}());

乍一看,你会认为getOrCreateCartId()是同步的,但这是async / await的影响,它允许异步代码的结构几乎与同步代码相同。

以下是对FOO.getOrCreateCartId()

的两次快速通话
// call from component 1
FOO.getOrCreateCartId().then(function(cartId) {
    console.log(cartId);
});
// call from component 2
FOO.getOrCreateCartId().then(function(cartId) {
    console.log(cartId);
});

即使来自组件1的呼叫需要呼叫create(),控制台也会记录两次相同的cartId。

DEMO:我添加了.clear()方法,因此您可以随心所欲地使用它并自行调试它可以正常工作。

相关问题