边缘情况下的IndexedDb事务自动提交行为

时间:2014-12-06 00:09:16

标签: javascript transactions indexeddb

Tx在以下情况下提交:

  • 请求成功回调返回      - 这意味着只有在从前一个成功回调执行下一个请求时,才能在事务边界内执行多个请求
  • 当您的任务返回事件循环时

这意味着如果没有提交请求,则在返回事件循环之前不会提交。这些事实构成了两个有问题的状态:

  • 通过将新任务从先前请求的成功回调中排队到事件循环队列而不是同步提交新请求来发出新的IDB请求
    • 在这种情况下,第一个成功回调会立即返回,但已安排另一个IDB请求
      • 是在单个初始事务中执行的所有异步请求吗?这是非常重要的,如果你想用背压实现结果拉动,消费者以未来的形式给你一个反馈,它准备好消耗另一个反应
  • 创建一个ReadWrite tx,在返回事件循环之前不对其发出任何请求并创建另一个请求
    • 是否创建了一个新的隐式提交前一个tx?如果不是,可能会发生严重的写锁定,因为:
  

如果多个“readwrite”事务试图访问它们   对象存储(即,如果它们具有重叠的范围),该事务   首先创建的必须是可以访问的事务   对象存储首先。由于以前的要求   段落,这也意味着它是唯一拥有的交易   在事务完成之前访问对象库。

通过带有反压的递归请求提交从成功回调中将新任务排入事件循环队列的示例:

    function recursiveFn(key) {
      val req = store.get(key)
      req.onsuccess = function() {
        observer.onNext(req.result).onsuccess { recursiveFn(nextKey) } 
      }
    }

Observer#onNext // returns Future[Ack] Ack is either Continue or Cancel

现在可以onsuccessonNext执行setTimeout(0)或不使整个事情成为一个事务的一部分吗?

奖金问题:

我认为ReadOnly事务是暴露给消费者/用户的,因为如果你从前一个成功回调中递归提交新请求,那么很难检测到批量读取的结束吗?否则我没有看到任何其他原因让他们接触到用户,对吗?

1 个答案:

答案 0 :(得分:2)

我不确定我是否完全理解您的问题,但我会就是否可以安全地使用IDB事务事件来移动状态机提供答案。

是和否。在理论上是的,在实践中没有。

我认为您了解交易lifetime。但是rehash

  

事务的生命周期持续时间与引用一样长:只要它被引用,它就是“活动的”,之后它被称为“已完成”并且事务已被提交。

理论上,只要事务成功提交,oncomplete就会触发。 spec中有一个有用的提示,表明你可以循环:

  

要确定事务是否已成功完成,请侦听事务的complete事件而不是IDBObjectStore.add请求的成功事件,因为事件在成功事件触发后仍可能失败。

要安全使用此机制,请务必关注包含onblockedonabort在内的非成功事件。

实际上,我发现交易在长期存在或连续分批完成时会变得非常复杂(正如您在另一个IDB评论中所指出的那样)。我通常不会将我的应用程序设计为需要棘手的行为,因为无论规范如何说它应该是行为,我都会在Firefox和Chromium中看到不稳定的交易(但主要是Blink,有趣的是),尤其是当多个标签打开时。 / p>

我花了很多时间重写dash来重用事务以获得所谓的性能提升。最后它甚至无法通过我的基本写测试,我被迫放弃同步/排队/连续交易并再次重写。这次我选择了一次一次交易的模型,这个模型速度较慢,但​​对我来说,更可靠(建议避免使用我的lib并使用ydn进行批量插入)。

我不确定您的应用程序要求,但我认为将您的I / O绑定到事件循环中似乎是一个灾难性的想法。如果我需要一个事件循环,就像我理解的那样,我肯定会使用requestAnimationFrame()来限制回调,如果我需要更少的刻度而不是每33毫秒一个。