首页 > 解决方案 > indexeddb/localforage 读取是否从同步缓冲区解析?

问题描述

采用以下伪代码

localforageStore.setItem('foo', 'bar')
    .then(console.log('foo is persisted to disk')); 
localforageStore.getItem('foo')
    .then(v => console.info('foo is '+v));   // A, B or C? 

是console.info:-

即,即使写入磁盘是异步的,同步读取是否会从 indexeddb 和/或 localforage 内部的缓冲区解析?

标签: javascriptindexeddblocalforage

解决方案


我查看了https://github.com/localForage/localForage/blob/master/src/drivers/indexeddb.js上的 localForage indexedDB 驱动程序。我没有看到任何缓冲。因此,没有什么可以getItem从某个缓冲区中获取。

更具体地说,再次查看 localForage 源代码,我可以看到它是 indexedDB 事务的基本承诺包装器setItemgetItem这些包装器在事务完成时解析。这告诉我 indexedDB 控制非阻塞行为,而不是 localForage。

因此,由于 indexedDB 负责,这意味着我们可以查看 indexedDB 行为来帮助回答您的问题。我们发出两笔交易,每笔都有一个请求。第一个是来自 的读写事务setItem,第二个是来自 的只读事务getItem

通常,交易可以重叠。例如,您可以同时运行 100 个只读事务。但是,读写事务会阻止其他事务以确保数据完整性。读写事务不能重叠。

由于您可以触发并忘记调用事物,因此这有点复杂。您可以同时启动两个事务,而无需等到第一个事务完成后才开始第二个事务。请注意开始运行某些东西与实际上将其视为运行之间的区别。

因此,查看您的代码,setItem('foo', 'bar')开始一个读写事务,然后 getItem('foo') 开始一个只读事务。在开始只读事务之前,您无需等待读写事务承诺包装器解决。

虽然这在表面上确实是一种非阻塞方法,但它在 indexedDB 层内仍然是技术上的阻塞,因为只读事务将阻塞(无限期地等待)同一对象存储上的先前读写事务解决。

这就是我认为引起混乱的原因。因为我们知道 readonly 事务是在 readwrite 启动之后启动的,所以我们知道 readonly 事务在技术上总是只会在 readwrite 事务之后才解决,因为它不可能在它之前解决,也不可能与它同时解决。

因此,您可以说答案是 A。因为只读事务必须等待读写事务完成。它在 localForage 承诺层是不确定的,但在 indexedDB 事务层是确定的。

在https://www.w3.org/TR/IndexedDB-2/#transaction-construct查看规范以获得更多技术解释

这是一个相关部分(强调我的):

如果多个读/写事务试图访问同一个对象存储(即,如果它们具有重叠范围),则首先创建的事务必须是首先访问对象存储的事务。由于上一段中的要求,这也意味着它是唯一可以访问对象存储的事务,直到事务完成。

在读/写事务之后创建的任何事务都必须看到读/写事务写入的更改。因此,如果创建了一个读/写事务 A,然后又创建了另一个事务 B,并且这两个事务具有重叠范围,那么 B 必须看到对属于该重叠范围的任何对象存储所做的任何更改。由于上一段中的要求,这也意味着 B 事务在 A 事务完成之前无法访问该重叠范围内的任何对象存储。

一般来说,上述要求意味着任何与读/写事务具有重叠范围并且在该读/写事务之后创建的事务不能与该读/写事务并行运行。


推荐阅读