从多个javascript线程访问IndexedDB

Sha*_*awn 9 javascript web-worker indexeddb

概述: 我试图通过从网页和Web工作者访问IndexedDB来避免竞争条件.

设置: 当用户使用站点时,将项目保存到本地IndexedDB的网页.只要用户将数据保存到本地DB,记录就会标记为"未发送".

Web工作者后台线程,它从IndexedDB中提取数据,将其发送到服务器,并在服务器收到后,将IndexedDB中的数据标记为"已发送".

问题: 由于对IndexedDB的访问是异步的,因此无法保证用户不会在Web工作者将其发送到服务器的同时更新记录.时间表如下所示:

  1. Web工作者从数据库获取数据并将其发送到服务器
  2. 当传输发生时,用户更新数据将其保存到DB.
  3. Web工作者从服务器获取响应,然后将数据库更新为"已发送"
  4. 现在DB中的数据尚未发送到服务器但标记为"已发送"

解决方案失败: 从服务器获得响应后,我可以重新检查行以查看是否有任何更改.但是我仍然留有一个小窗口,可以将数据写入数据库,并且永远不会将其发送到服务器.

示例:服务器说保存数据后,然后:

IndexedDB.HasDataChanged(
    function(changed) { 
        // Since this is async, this changed boolean could be lying.
        // The data might have been updated after I checked and before I was called.
        if (!changed){ 
          IndexedDB.UpdateToSent() }
    });
Run Code Online (Sandbox Code Playgroud)

其他说明: 根据W3规范有一个sync api,但还没有人实现它,因此无法使用它(http://www.w3.org/TR/IndexedDB/#sync-database).sync api旨在供网络工作者使用,以避免我假设的这种情况.

对此的任何想法将不胜感激.已经工作了大约一个星期,并且无法想出任何可行的方法.

Sha*_*awn 3

我想我现在找到了解决这个问题的方法。并不像我想要的那么干净,但它似乎是线程安全的。

每当我更新数据时,我首先将日期时间存储到 LastEdit 字段中。我从网络工作者那里向浏览器发布一条消息。

self.postMessage('UpdateDataSent#' + data.ID + '#' + data.LastEdit);
Run Code Online (Sandbox Code Playgroud)

然后在浏览器中,只要上次编辑日期没有改变,我就会更新我的发送标志。

// Get the data from the DB in a transaction
if (data.LastEdit == lastEdit)
{
    data.Sent = true;
    var saveStore = trans.objectStore("Data");
    var saveRequest = saveStore.put(data);
    console.log('Data updated to Sent');
}
Run Code Online (Sandbox Code Playgroud)

由于这一切都是在浏览器端的事务中完成的,因此看起来工作正常。一旦浏览器支持 Sync API,我就可以把它全部扔掉。