are indexeddb/localforage reads resolved from a synchronous buffer?

时光怂恿深爱的人放手 提交于 2021-01-27 05:35:22

问题


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? 

Is the console.info:-

  • A. Guaranteed to display 'bar'

  • B. Guaranteed to display 'undefined'

  • C. Indeterminate

i.e. even though the write to disc is async, will a synchronous read be resolved from a buffer internal to indexeddb and/or localforage?


回答1:


I took a look at the localForage indexedDB driver at https://github.com/localForage/localForage/blob/master/src/drivers/indexeddb.js. I do not see any buffering. Therefore, there is nothing for the getItem to grab from some buffer.

More specifically, looking at the localForage source again, I can see that setItem and getItem are basic promise wrappers around indexedDB transactions. Those wrappers resolve when the transactions complete. This tells me that indexedDB is what controls the non-blocking behavior, not localForage.

So, because indexedDB is in charge, this means we can look at indexedDB behavior to help answer your question. We are issuing two transactions, each with a request. The first is a readwrite transaction from setItem, and the second is a readonly transaction from getItem.

Ordinarily, transactions can overlap. For example, you can have 100 readonly transactions all running at the same time. However, readwrite transactions block other transactions in order to ensure data integrity. readwrite transactions cannot overlap.

This gets complicated a bit by the fact that you can fire and forget call things. You can init two transactions at the same time, without waiting to start the second until after the first completes. Note the difference between starting to run something, and actually have it be considered running.

So, looking at your code, setItem('foo', 'bar') starts a readwrite transaction, and getItem('foo') starts a readonly transaction. You are not waiting for the readwrite transaction promise wrapper to settle before starting the readonly transaction.

While that is indeed a non-blocking approach on the surface, it is still technically blocking within the indexedDB layer, because the readonly transaction will block (wait, indefinitely) for the prior readwrite transaction on the same object store to settle.

And this is what I think causes confusion. Because we know the readonly transaction was started after the readwrite was started, we know that the readonly transaction will technically always resolve only after the readwrite transaction, because it cannot possibly resolve before it, nor at the same time as it.

Therefore, you can say the answer would be A. Because the readonly transaction has to wait for the readwrite transaction to complete. It is indeterminate at the localForage promise layer, but determinate at the indexedDB transaction layer.

Look at the spec for some more technical explanation at https://www.w3.org/TR/IndexedDB-2/#transaction-construct

Here is a relevant section (emphasis mine):

If multiple read/write transactions are attempting to access the same object store (i.e. if they have overlapping scope), the transaction that was created first must be the transaction which gets access to the object store first. Due to the requirements in the previous paragraph, this also means that it is the only transaction which has access to the object store until the transaction is finished.

Any transaction created after a read/write transaction must see the changes written by the read/write transaction. So if a read/write transaction, A, is created, and later another transaction B, is created, and the two transactions have overlapping scopes, then B must see any changes made to any object stores that are part of that overlapping scope. Due to the requirements in the previous paragraph, this also means that the B transaction does not have access to any object stores in that overlapping scope until the A transaction is finished.

Generally speaking, the above requirements mean that any transaction which has an overlapping scope with a read/write transaction and which was created after that read/write transaction, can’t run in parallel with that read/write transaction.



来源:https://stackoverflow.com/questions/54956481/are-indexeddb-localforage-reads-resolved-from-a-synchronous-buffer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!