Javascript 如何实现异步锁或者是全局单例?

我想要通过 JS 实现全局单例的对象缓存,但似乎都没有很好的解决办法。

目前环境:node + vue 浏览器端运行

let cache = [];
async function getUser(id){
    return new Promise((resolve) => {
        if(Object.prototype.hasOwnProperty.call(cache, id)){
            return resolve(cache[id])
        }
        setTimeout(() => {
            const obj = {
                id:id,
                name:Math.random() .toString(36)
            }
            cache[id] = obj
            resolve(obj)
        }, 200);
    })
}

如,上面代码是通过ID获取一个用户对象,而这个用户对象本想缓存起来,反复利用。其中的setTimeout是表示从网络资源获取或者是从数据库获取都将会是异步操作反馈。

> getUser(1).then(data=>console.log(data))
getUser(1).then(data=>console.log(data))
getUser(1).then(data=>console.log(data))

< Promise {<pending>}
VM323:1 {id: 1, name: "0.gayf057xhjo"}
VM323:2 {id: 1, name: "0.owi31fi79z"}
VM323:3 {id: 1, name: "0.3bya3r4poxn"}

如果连续执行多次,就会产生多个"用户对象", 通过名字鉴别,是因为缓存还未写入,导致后面的函数也会进入重新获取对象产生"新对象",前者先执行完毕写入的缓存对象也会被后来者覆盖,这是不被允许的。

如果之后再次获取,命中缓存了,获取到最后一次存储的缓存对象,前几次冗余的就会失效。

问题:

这个逻辑中,我想解决唯一缓存对象,或者是异步锁的实现,能够有效阻塞后来者,但不丢弃。

至于为什么要一起异步并发执行,而不逐个执行,是因为实际应用场景中,可能是有多个模块某个瞬间同时需要这块数据造成的。

希望各位大佬帮忙看看,提供思路方法。

阅读 5.6k
3 个回答

getUser连续运行多次,因为同步的原因,没有走上面的if,都走了下面的定时器,2s后添加cache(此时才有的cache[id],在运行getUser才会走if里)并resolve,所以每一次都不一样。改的话可以这么改,cache中不存放具体数据,而是存放promise实例

let cache = {};
async function getUser(id){
    return cache[id] || (cache[id] = new Promise(resolve => {
        setTimeout(() => {
            const obj = {
                id:id,
                name:Math.random() .toString(36)
            }
            resolve(obj)
        }, 200);
    }))
}

getUser(1).then(data=>console.log(data))
getUser(1).then(data=>console.log(data))
getUser(1).then(data=>console.log(data))

直接在cache[id]放个promise,检查这个promise的状态就知道要不要反复设置

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题