当 indexedDB 被阻止时,应用程序应该如何反应

How should an app react when indexedDB is blocked

我在另一个 中被告知要检测 "A blocked open (or delete) is not canceled, just... blocked. Once unblocked the open (or delete) will proceed."

的阻止和取消阻止事件

我想知道应用应该如何响应被阻止的事件,如果成功事件之后的路径最终仍然会发生的话。

如果我希望我的应用快速响应,并且遇到被阻止的事件,我是否应该取消成功路径?通过路径,我指的是在成功打开数据库的情况下执行的一系列语句和函数调用和延续。

之前我假设被阻止的事件阻止了成功路径的继续。我已经编写了我的应用程序来将被阻止的事件视为类似于错误,这意味着操作无法继续,并且应该报告错误,然后去做其他事情或 return 进入空闲状态。

我的问题是,如果成功事件最终可以继续,那么这意味着我正在分叉,错误路径和成功路径都会进行评估,并且可能会导致一些不需要的行为。

或者我最初的理解是正确的,我不需要担心取消成功时发生的事情,因为如果onblocked触发那么我可以安全地推断onsuccess不会。

做下面这样的事情感觉真的很丑陋,但这是唯一立即想到的可以避免我的问题的方法。

var r indexedDB.open(...);
var wasPreviouslyBlocked = false;
r.onsuccess = function() {
  // Cancel the success if previously blocked
  if(wasPreviouslyBlocked) {
    return;
  }
  // Proceed as normal
  doNextThing();
};
r.onblocked = function() {
  wasPreviouslyBlocked = true;
};

有没有更好的方法来应对这种情况?

The problem for me is that if the success event can eventually continue, then this means I am forking, and both the error path and the success path will evaluate, and will probably result in some unwanted behavior.

没错。

Or is my initial understanding correct, and I do not need to worry about canceling the things that happen onsuccess, because if onblocked fires then I can safely infer that onsuccess will not.

如有疑问,请实际尝试!您只需要几个选项卡和一个本地服务器。将日志记录添加到请求的 blockedsuccessupgradeneeded 处理程序以及连接的 versionchange 处理程序。

作为背景,假设一个选项卡打开数据库的 v1:

var r = indexedDB.open('db', 1);
r.onupgradeneeded = function(e) {
var db = r.result;
  // schema v1: has store s1
  db.createObjectStore('s1');
};
r.onsuccess = function(e) {
  window.db = r.result;
};

现在打开第二个选项卡并拉下要进行升级的较新代码:

var r = indexedDB.open('db', 2);
r.onupgradeneeded = function(e) {
  // schema v1: has store s1
  // schema v2: adds store s1
  var db = r.result;
  if (e.oldVersion < 1) {
    db.createObjectStore('s1');
  }
  db.createObjectStore('s2');
};
r.onblocked = function(e) {
  console.log('uh oh...');
};

至少可以采用三种通用方法来应对升级受阻的情况。

  1. 让 "old" 连接监视 versionchange 事件并及时关闭以解锁升级。
  2. 让 "new" 连接监视 blocked 事件并通知用户关闭其他选项卡
  3. 让 "new" 连接监视 blocked 事件并忽略升级。

既然您对 #3 感兴趣,那么您将如何实现它:

var r = indexedDB.open('db', 2);
r.onupgradeneeded = function(e) {

  // If we ever saw a blocked event, abort this upgrade.
  if (r.was_blocked) {
    r.transaction.abort();
    return;
  }

  var db = r.result;
  if (e.oldVersion < 1) {
    db.createObjectStore('s1');
  }
  db.createObjectStore('s2');
};

r.onblocked = function(e) {
  // Record that we saw a blocked event so this upgrade
  // can be ignored.
  r.was_blocked = true;
};

这与您在 wasPreviouslyBlocked 尝试中的结果非常接近,但是您的代码中存在一个严重错误:您没有中止升级,只是没有实际修改架构.因此,您最终会得到一个具有模式版本 2 但没有任何来自 v2 的更改的数据库。如果数据库再次打开,它将已经是 v2,因此升级不会触发,您将错过预期的架构更改。