随着前端应用越来越复杂,大量使用本地存储已成为一种常见的做法。然而,本地存储中存在一种竞争条件,如果多个窗口或 tab 同时更新同一个键值对的值,则可能导致数据错误。ES9 中,为了避免这种问题,引入了 Atomic Storage 提案,本文就介绍如何使用该提案消除本地存储中的竞争条件。
Atomic Storage 简介
Atomic Storage 提案定义了一系列的原子操作 API,可以确保对同一个键值对的多次修改是以原子形式执行的。原子操作是不可分割的,要么全部成功,要么全部失败,保证了数据的一致性和完整性。
目前,Atomic Storage 提案还在草案阶段,但已经有些浏览器开始支持了,比如 Firefox Nightly、Chrome Canary 等。如果当前浏览器不支持该提案,可以使用 idb-keyval 库进行模拟。
如何使用 Atomic Storage
下面通过一个示例来演示如何使用 Atomic Storage。
假设有两个窗口 A 和 B,都需要操作一个名为 count 的键值对,用来统计用户点击一个按钮的次数。我们需要保证两个窗口的操作是互相独立的,不会出现数据错乱的情况。
普通本地存储
// javascriptcn.com 代码示例 // A 页面的代码 const count = localStorage.getItem('count') || 0 document.getElementById('count').textContent = count document.getElementById('btn').addEventListener('click', () => { const newCount = parseInt(localStorage.getItem('count')) + 1 localStorage.setItem('count', newCount) document.getElementById('count').textContent = newCount }) // B 页面的代码 window.addEventListener('storage', e => { if (e.key === 'count') { document.getElementById('count').textContent = e.newValue } })
上述代码中,窗口 A 用 localStorage 来存储 count 值,每次点击按钮都会将 count 加1,然后更新 UI。窗口 B 监听 localStorage 的 storage 事件来获取 count 值的变化。
然而,这种实现方式容易出现竞争条件,窗口 A 和 B 可能会同时修改同一个 count 值,这样就会出现数据不一致的情况。
使用 Atomic Storage
// javascriptcn.com 代码示例 // A 页面的代码 const store = new AtomicLocalStorage() const count = await store.getItem('count') || 0 document.getElementById('count').textContent = count document.getElementById('btn').addEventListener('click', async () => { const newCount = parseInt(await store.getItem('count')) + 1 await store.setItem('count', newCount) document.getElementById('count').textContent = newCount }) // B 页面的代码 const store = new AtomicLocalStorage() store.observe('count', newValue => { document.getElementById('count').textContent = newValue })
这里使用 AtomicStorage 的 AtomicLocalStorage 类来进行存储操作,具体使用方式和普通的 localStorage 差不多。不同的是,AtomicLocalStorage 的 getItem 和 setItem 方法都是异步的,因为它们需要原子操作。
另外,还引入了 observe 方法,用来监听特定键值对的变化。该方法会在键值对的值发生变化时触发回调函数,该回调函数的参数是变化后的值,可以用来更新页面。
总结
本文介绍了如何使用 ES9 提供的 Atomic Storage 来消除本地存储中的竞争条件。Atomic Storage 定义了一些原子操作的 API,保证了对同一个键值对的多次修改是以原子形式执行的,避免了数据出现不一致的情况。我们可以使用 AtomicLocalStorage 类来进行存储操作,并使用 observe 方法来监听键值对的变化。如果当前浏览器不支持该提案,可以使用 idb-keyval 库进行模拟。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65338bd57d4982a6eb718ef2