Tom*_*ver 5 javascript promise indexeddb
刚刚开始我的第一个使用IndexedDb的项目,我很难在第一次使用时创建一个用于打开和升级数据库的系统.我想使用promises(当前的angularJs$q服务,但我很灵活)给我一些关于捕获任何错误的保证,并减少关于失败模式的心理开销推理.我的要求是:
到目前为止我遇到的问题:
onupgraderequired如果DB不需要升级(这样一个承诺,得到了在升级完成解决将永远不会得到解决,如果DB不需要升级回调不叫,并调用代码不知道这是否会是这样接线回调时)onsuccess回调被调用 - 因此每次升级都需要顺序链接onsuccess调用第一个回调时,该versionchange事务不再处于活动状态.我目前的结论是,API基本上对基于承诺的方法持敌对态度.我最好的尝试在下面(简化了一点以便于阅读).我哪里错了?
var newPromise = function(withDeferred) {
var deferred = $q.defer();
try {
withDeferred(deferred);
} catch (err) {
deferred.reject(err);
}
return deferred.promise;
};
var newTransactionPromise = function(getTransaction) {
return newPromise(function(deferred) {
var transaction = getTransaction();
transaction.oncomplete = function(ev) { deferred.resolve(); };
transaction.onabort = function(ev) { deferred.reject(transaction.error); };
});
};
var migrations = [
function(db) {
return newTransactionPromise(function() {
// throws: The database is not running a version change transaction.
return db
.createObjectStore("entries", { keyPath: 'id', autoIncrement: true })
.transaction;
});
},
function(db) {
return newTransactionPromise(function()
{
var entryStore = db.transaction("entries", "readwrite").objectStore("entries");
entryStore.add({ description: "First task" });
return entryStore.transaction;
});
}
];
var upgradeAndOpen = function() {
return newPromise(function(deferred) {
var latest_version = migrations.length;
var request = indexedDB.open("caesium", latest_version);
request.onupgradeneeded = function(event) {
try {
// create an already resolved promise to start a chain
var setupDeferred = $q.defer();
setupDeferred.resolve();
var setupComplete = setupDeferred.promise;
for (var v = event.oldVersion; v < latest_version; v++)
{
// Problem: the versionchange transaction will be 'inactive' before this promise is scheduled
var nextMigration = migrations[v].bind(this, request.result);
setupComplete = setupComplete.then(nextMigration);
}
setupComplete["catch"](deferred.reject);
} catch (err) {
deferred.reject(err);
}
};
request.onerror = function(event) { deferred.reject(request.error); };
request.onsuccess = function(event) { deferred.resolve(request.result); };
});
};
upgradeAndOpen()["catch"](function(err) { $scope.status = err; });
Run Code Online (Sandbox Code Playgroud)
我终于找到了一种方法来避免这个 API 的所有麻烦,并找到了一个解决方案,该解决方案公开了一个干净的基于承诺的接口,并推广到任意数量的数据库迁移。关键问题:
versionchange;versionchange,因此我们必须区分数据迁移和模式迁移,并通过不同的事务以不同的方式执行它们。versionchange,但不能通过通常的db.transaction('readwrite', ...).objectstore(...)方法执行 - 这会引发异常。而是使用对交易的引用versionchange。.open(dbName, version)只允许一笔versionchange交易,一旦成功就消失了。versionchange该方法是创建交易的唯一方法.open(dbName, version)versionchange当其他数据库连接打开时,事务会阻塞,因此在尝试链中的下一次迁移之前必须关闭每个连接。我为协商所有这些问题而想出的代码如下。
var newPromise = function(withDeferred) {
var deferred = $q.defer();
try {
withDeferred(deferred);
} catch (err) {
deferred.reject(err);
}
return deferred.promise;
};
var newTransactionPromise = function(getTransaction) {
return newPromise(function(deferred) {
var transaction = getTransaction();
transaction.oncomplete = function(ev) { deferred.resolve(); };
transaction.onabort = function(ev) { deferred.reject(transaction.error); };
});
};
var newMigrationPromise = function(dbName, version, migration) {
return newPromise(function(deferred) {
var request = indexedDB.open(dbName, version);
// NB: caller must ensure upgrade callback always called
request.onupgradeneeded = function(event) {
var db = request.result;
newTransactionPromise(
function() {
migration(db, request.transaction);
return request.transaction;
})
.then(function() { db.close(); })
.then(deferred.resolve, deferred.reject);
};
request.onerror = function(ev) { deferred.reject(request.error); };
});
};
var migrations = [
function(db, transaction) {
db.createObjectStore("entries", { keyPath: 'id', autoIncrement: true });
},
function(db, transactionn) {
db.createObjectStore("entries2", { keyPath: 'id', autoIncrement: true });
},
function(db, transaction) {
var entryStore = transaction.objectStore("entries");
entryStore.add({description: "First task"});
}
];
var upgradeAndOpen = function() {
return open()
.then(function(db) {
var version = db.version;
db.close(); // this connection will block the upgrade (AFAICT)
return version;
})
.then(function(version) {
return newPromise(function(deferred) {
// version when created but empty is v1
// so after the first migration (index: 0) the version must be 2
var migrationsPerformed = version - 1;
var migrationCount = migrations.length;
var previousMigration = newPromise(function(deferred) { deferred.resolve(); });
for (var index = migrationsPerformed; index < migrationCount; index++)
{
var performNextMigration = newMigrationPromise.bind(this, "caesium", index+2, migrations[index]);
previousMigration = previousMigration.then(performNextMigration);
}
previousMigration.then(deferred.resolve, deferred.reject);
});
})
.then(open);
};
var open = function() {
return newPromise(function(deferred) {
var request = indexedDB.open("caesium");
request.onsuccess = function(ev) { deferred.resolve(request.result); };
request.onerror = function(ev) { deferred.reject(request.error); };
});
};
upgradeAndOpen()
.then(function() { $scope.status = "completed"; }, function(err) { $scope.status = err; });
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3633 次 |
| 最近记录: |