从多个 JavaScript 线程访问 IndexedDB

发布于 2024-12-29 07:01:10 字数 1130 浏览 1 评论 0原文

概述: 我试图避免从网页和网络工作人员访问 IndexedDB 时出现竞争情况。

设置: 当用户使用站点时将项目保存到本地 IndexedDB 的网页。每当用户将数据保存到本地数据库时,记录就会被标记为“未发送”。

Web-worker 后台线程从 IndexedDB 中提取数据,将其发送到服务器,服务器收到数据后,将 IndexedDB 中的数据标记为“已发送”。

问题: 由于对 IndexedDB 的访问是异步的,我不能保证用户不会在网络工作人员将记录发送到服务器的同时更新记录。时间线如下所示:

  1. Web-worker 从数据库获取数据并将其发送到服务器
  2. 在传输发生时,用户更新数据并将其保存到数据库。
  3. Web Worker 从服务器获取响应,然后将数据库更新为“已发送”
  4. 现在数据库中存在尚未发送到服务器但标记为“已发送”的数据

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

例子: 服务器表示数据已保存后,然后:

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() }
    });

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

任何对此的想法将不胜感激。已经研究了大约一周,但还没有想出任何可行的办法。

Overview:
I am trying to avoid a race condition with accessing an IndexedDB from both a webpage and a web-worker.

Setup:
Webpage that is saving items to the local IndexedDB as the user works with the site. Whenever a user saves data to the local DB the record is marked as "Unsent".

Web-worker background thread that is pulling data from the IndexedDB, sending it to the server and once the server receives it, marking the data in the IndexedDB as "Sent".

Problem:
Since access to the IndexedDB is asynchronous, I can not be guaranteed that the user won't update a record at the same time the web-worker is sending it to the server. The timeline is shown below:

  1. Web-worker gets data from DB and sends it to the server
  2. While the transfer is happening, the user updates the data saving it to the DB.
  3. The web-worker gets the response from the server and then updates the DB to "Sent"
  4. There is now data in DB that hasn't been sent to the server but marked as "Sent"

Failed Solution:
After getting the response from the server, I can recheck to row to see if anything has been changed. However I am still left with a small window where data can be written to the DB and it will never be sent to the server.

Example:
After server says data is saved, then:

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() }
    });

Other notes:
There is a sync api according to the W3 spec, but no one has implemented it yet so it can not be used (http://www.w3.org/TR/IndexedDB/#sync-database). The sync api was designed to be used by web-workers, to avoid this exact situation I would assume.

Any thoughts on this would be greatly appreciated. Have been working on it for about a week and haven't been able to come up with anything that will work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

只想待在家 2025-01-05 07:01:10

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

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

self.postMessage('UpdateDataSent#' + data.ID + '#' + data.LastEdit);

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

// 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');
}

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

I think I found a work around for this for now. Not really as clean as I would like, but it seems to be thread safe.

I start by storing the datetime into a LastEdit field, whenever I update the data.
From the web-worker, I am posting a message to the browser.

self.postMessage('UpdateDataSent#' + data.ID + '#' + data.LastEdit);

Then in the browser I am updating my sent flag, as long as the last edit date hasn't changed.

// 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');
}

Since this is all done in a transaction in the browser side, it seems to work fine. Once the browsers support the Sync API I can throw it all away anyway.

空宴 2025-01-05 07:01:10

旧线程,但使用事务可以解决失败的解决方案方法。即,事务仅需要检查 IndexedDB 中的数据在发送后没有更改,如果没有更改,则将其标记为已发送。如果发生变化,事务将在不写入的情况下结束。

Old thread but the use of a transaction would solve the Failed Solution approach. I.e. the transaction only needs to span the check that the data in the IndexedDB hasn't change after the send and marking it as sent if there was no change. If there was a change, the transaction ends without writing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文