【问题标题】:How to close and re-open indexedDB database without reloading the page?如何在不重新加载页面的情况下关闭并重新打开 indexedDB 数据库?
【发布时间】:2020-03-04 03:21:43
【问题描述】:

在尝试捕获与 indexedDB 数据库请求相关的错误并提供挽救数据库的选项时,我想提供关闭数据库、重新打开数据库以及重置 RAM 中保存的映射数据值的选项。因为该页面是由扩展程序操作的,所以我不希望用户刷新浏览器,而是使用自定义错误对话框中提供的按钮。

看起来很简单,但我一定错过了一些重要的事情。 close 方法不返回承诺,但 MDN documents 状态它立即返回并在单独的线程中关闭数据库。在使用db.close() 之前,我尝试定义一个简单的事件侦听器db.addEventListener( 'close', handler, false )(如here 所述),但它从未被调用过。数据库似乎关闭了,因为在单击该按钮后,其余的数据库操作不再起作用。我想在数据库关闭后重新打开它,因为这将触发一组初始化步骤并尝试重新启动而不重新加载页面。

我的问题是如何在尝试再次打开数据库之前监听数据库close 事件以及如何知道close 方法是否失败?

谢谢。

function DB_restart() 
  { 
    DB.addEventListener( 'close', expected, false );
    DB.close();

    function expected( evt )
      {
        console.log( 'closed' );
        console.log( evt ); 
        // ... DB_open() ...
       }
} // close DB_restart

我之前没有注意到 MDN 上的 this 信息,其中指出 close 事件在使用 close 方法时不会触发,但前提是它是意外的,@Josh 在答案中指出似乎随后被删除。所以,上面的行不通。

也许,因为在这种情况下,可以确定所有事务都已关闭,并且在新的open 之前请求close,所以关闭总是首先完成。到目前为止,在这种情况下,紧随其后的数据库打开调用 db.close() 一直有效。


在进一步解决这个问题后,对于我简单的重启或重置情况,似乎不需要关闭数据库,至少在 Firefox 中是这样。目标是重新初始化映射变量,就像在不重新加载页面的情况下加载页面时一样,并且由IDBFactory.open()onsuccess 事件触发。尝试打开已打开的数据库似乎仍会触发 onsuccess 事件,而不是错误或静默忽略请求。由于我没有更改版本,如果这是正常响应,则无需关闭。似乎在 open 之前立即使用 close 也有效,因为在过去的几天里,它在测试中没有出错一次;但是,在这种情况下,已知没有待处理的未结交易。

【问题讨论】:

  • 这感觉就像XY problem:实际发生了什么让您认为解决方案是关闭并重新打开数据库?
  • 我只是想设置错误捕获选项,以防发生某些事情,其中​​大部分是特定的;但是,如果这些都失败了,我想把它作为一个选项,以防 RAM 中保存的映射数据与数据库中的映射数据不再一致。
  • 关闭和重新打开数据库不会更改该数据库中的数据,因此根据您的描述,这完全是一个问题:您是否只是从数据库同步回来,或者您是否首先关闭它然后重新打开它并然后从数据库同步。那么为什么要关闭并重新打开呢?
  • 目标是在任何情况下都不让程序失败、冻结或显示由“坏”数据构建的任何内容。当出现数据问题时,错误捕获可能会导致死胡同;除了虚构的场景之外,错误捕获是不可预测的,因为我们所知道的只是引发错误的代码块。这种方法现在有效,至少对于捏造的错误。只有当内存中的映射数据与数据库不一致时,它才能纠正问题,但它也可以让用户摆脱死胡同,并允许事后纠正。
  • 那么恐怕我不知道您在这里实际上要做什么,因为这听起来像是一种处理数据管理的非常奇怪的方式(您的 IndexedDB is 您的客户端,内存中的数据已经存储,因此“事物去同步”的解决方案是使用 IndexedDB,而不是将数据取出,将其存储在其他地方,然后由于数据库中的值而导致不同步已更改),但希望其他人在此问题上对您的需求有更好的了解。

标签: javascript indexeddb


【解决方案1】:

澄清几点:

  • "close" 事件仅在异常关闭时触发 - 例如磁盘已断开连接,检测到不可恢复的损坏等。从脚本调用close() 不会触发它。

  • 当调用close() 然后调用open()(没有版本冲突)时,如果有事务正在运行,新连接可能会在前一个连接关闭之前打开。您可以通过使用循环启动事务来观察这一点,该循环在前一个请求成功时发出新的 get() 请求(直到布尔变量设置为 true),保持运行,然后打开一个新连接,然后才停止打开成功后的循环(通过将布尔值设置为true)。

总体而言,尚不清楚您要问什么。如果您确定数据库中的数据本身是错误的,您可能想要 close() 并发出 deleteDatabase() 调用,并确保您的所有连接都执行 close() 以响应 "versionchange" 事件,以便删除没有被阻止。删除成功后,您可以重建/重新填充数据库。

【讨论】:

  • 感谢您的回复。我理解你的两颗子弹。在我的特殊情况下,我肯定会知道没有未结交易。数据由用户在扩展中作为用户“构建”添加,因此无法删除和重新加载 edatabse,因为当时数据仅存在于客户端上。因此,目的是“重置” RAM 和数据库中的一些映射字段,以尝试更正某些类型的错误,例如查找不再存在的 ket,因为删除操作以删除的方式失败记录但不更新映射数据。
  • 这完全取决于错误发生的位置。我尝试处理回滚以避免所有这些问题,但以防万一我错过了什么或出现电源故障,我想提供一种挽救数据库的方法。如果没有所有信息,这听起来可能很奇怪,但我发现错误处理非常困难,尤其是在涉及数据和映射时。尽管如此,我在问题中所说的仍然有效。无需关闭;尝试打开一个已经打开的数据库不会出错并再次触发 onsuccess 事件。
猜你喜欢
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 2014-05-13
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
相关资源
最近更新 更多