are indexeddb/localforage reads resolved from a synchronous buffer?

pin*_*yid 5 javascript indexeddb localforage

Taking the following pseudo code

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? 
Run Code Online (Sandbox Code Playgroud)

Is the console.info:-

  • A. Guaranteed to display 'bar'

  • B. Guaranteed to display 'undefined'

  • C. Indeterminate

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

Jos*_*osh 3

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

\n\n

更具体地说,再次查看 localForage 源代码,我可以看到setItem并且getItem是围绕 indexedDB 事务的基本承诺包装器。当交易完成时,这些包装器就会解析。这告诉我,控制非阻塞行为的是indexedDB,而不是localForage。

\n\n

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

\n\n

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

\n\n

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

\n\n

所以,看看你的代码,setItem(\'foo\', \'bar\')启动一个读写事务,然后 getItem(\'foo\') 启动一个只读事务。在启动只读事务之前,您不需要等待读写事务承诺包装器解决。

\n\n

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

\n\n

我认为这就是造成混乱的原因。因为我们知道只读事务是在读写事务启动之后启动的,所以我们知道只读事务在技术上总是只能在读写事务之后解析,因为它不可能在读写事务之前解析,也不可能与读写事务同时解析。

\n\n

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

\n\n

请参阅规范以获取更多技术说明:https://www.w3.org/TR/IndexedDB-2/#transaction-construct

\n\n

这是相关部分(重点是我的):

\n\n
\n

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

\n\n

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

\n\n

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

\n
\n