使用游标从 IndexedDb 获取一页结果
Getting a page of results from IndexedDb using cursor
我正在尝试学习如何使用 IndexedDb,我的下一步是从商店获取一页结果。我的策略是将为页面检索到的最后一个键存储在服务中,并使用它打开游标,并使用该键作为下一个请求的下限。这是我最初定义的函数:
service.getListPage = function(store, pageSize) {
pageSize = pageSize || 15;
var deferred = $q.defer();
//called on cursor open success event
var getPage = function (cursorEvent) {
var page = [];
var cursor = cursorEvent.target.result;
if (cursor) {
for (var i = 0; i < pageSize; i++) {
page.push(cursor.value);
cursor.continue();
}
lastKeyOnPage[store] = cursor.key;
deferred.resolve(page);
} else {
deferred.resolve([]);
}
}
var transaction = service.db.transaction([store], "readonly");
var objectStore = transaction.objectStore(store);
var cursor;
if (lastKeyOnPage.hasOwnProperty(store) && lastKeyOnPage[store]) {
cursor = objectStore.openCursor(IDBKeyRange.lowerBound(lastKeyOnPage[store]));
} else {
cursor = objectStore.openCursor();
}
cursor.onsuccess = getPage;
return deferred.promise;
}
如果我尝试对商店中的一件商品使用此功能,我 运行 会遇到两个问题:
- continue 函数会抛出错误(所以我使用了 try/catch,解析 catch 块中的值数组)
- 光标会 return 相同的值,
pageSize
次(所以我尝试检查当前循环迭代中的主键是否与最后一个匹配)
不过,这仍然无效。商店中现在有两个项目,如果我调用此函数,它会获取第一个项目,然后抛出一个错误,指出游标正在迭代或超过其末尾。
我是否遗漏了一些关于它应该如何工作的信息?我只想使用 getAll,但这是针对 Cordova 应用程序的,该方法不可用。我怎样才能只获取一定数量的结果?
我明白了。规范并没有使它完全显而易见,但是 onsuccess
事件处理程序是在调用 cursor.continue()
之后调用的,因此不需要显式循环。固定方法如下所示:
var pageFunction = function(store, pageSize, direction) {
pageSize = pageSize || defaultPageSize;
var deferred = $q.defer();
var counter = pageSize;
var page = [];
if (!keys[store]) {
keys[store] = {};
}
//query function
var getPage = function (cursorEvent) {
var cursor = cursorEvent.target.result;
if (cursor && (counter < 0 || counter--)) {
if (direction) {
if (counter == pageSize - 1) {
keys[store][direction == "prev" ? first : last] = cursor.key;
}
keys[store][direction == "prev" ? last : first] = cursor.key;
}
page.push(cursor.value);
cursor.continue();
}
}
var transaction = service.db.transaction([store], "readonly");
var objectStore = transaction.objectStore(store);
var rangeStart = null;
if (direction) {
var bound = direction == "prev" ? upperBound : lowerBound;
rangeStart = keys[store].first
? IDBKeyRange.bound(keys[store].first)
: null;
}
var cursor = objectStore.openCursor(rangeStart, direction);
cursor.onsuccess = getPage;
transaction.oncomplete = function () { deferred.resolve(q(page)); }
return deferred.promise;
}
var pageAvailability = function(bound) {
var deferred = $q.defer();
var transaction = service.db.transaction([store], "readonly");
var objectStore = transaction.objectStore(store);
var countRequest = objectStore.count();
cursor.onsuccess = function (response) {
deferred.resolve(response > 0);
}
return deferred.promise;
}
service.prevPage = function (store, pageSize) {
return pageFunction(store, pageSize, "prev");
}
service.hasPrev = function (store) {
return pageAvailability(IDBKeyRange.upperBound(keys[store].last));
}
service.hasNext = function() {
return pageAvailability(IDBKeyRange.lowerBound(keys[store].first));
}
service.nextPage = function(store, pageSize) {
return pageFunction(store, pageSize, "next");
}
service.thisPage = function(store, pageSize) {
return pageFunction(store, pageSize);
}
我正在尝试学习如何使用 IndexedDb,我的下一步是从商店获取一页结果。我的策略是将为页面检索到的最后一个键存储在服务中,并使用它打开游标,并使用该键作为下一个请求的下限。这是我最初定义的函数:
service.getListPage = function(store, pageSize) {
pageSize = pageSize || 15;
var deferred = $q.defer();
//called on cursor open success event
var getPage = function (cursorEvent) {
var page = [];
var cursor = cursorEvent.target.result;
if (cursor) {
for (var i = 0; i < pageSize; i++) {
page.push(cursor.value);
cursor.continue();
}
lastKeyOnPage[store] = cursor.key;
deferred.resolve(page);
} else {
deferred.resolve([]);
}
}
var transaction = service.db.transaction([store], "readonly");
var objectStore = transaction.objectStore(store);
var cursor;
if (lastKeyOnPage.hasOwnProperty(store) && lastKeyOnPage[store]) {
cursor = objectStore.openCursor(IDBKeyRange.lowerBound(lastKeyOnPage[store]));
} else {
cursor = objectStore.openCursor();
}
cursor.onsuccess = getPage;
return deferred.promise;
}
如果我尝试对商店中的一件商品使用此功能,我 运行 会遇到两个问题:
- continue 函数会抛出错误(所以我使用了 try/catch,解析 catch 块中的值数组)
- 光标会 return 相同的值,
pageSize
次(所以我尝试检查当前循环迭代中的主键是否与最后一个匹配)
不过,这仍然无效。商店中现在有两个项目,如果我调用此函数,它会获取第一个项目,然后抛出一个错误,指出游标正在迭代或超过其末尾。
我是否遗漏了一些关于它应该如何工作的信息?我只想使用 getAll,但这是针对 Cordova 应用程序的,该方法不可用。我怎样才能只获取一定数量的结果?
我明白了。规范并没有使它完全显而易见,但是 onsuccess
事件处理程序是在调用 cursor.continue()
之后调用的,因此不需要显式循环。固定方法如下所示:
var pageFunction = function(store, pageSize, direction) {
pageSize = pageSize || defaultPageSize;
var deferred = $q.defer();
var counter = pageSize;
var page = [];
if (!keys[store]) {
keys[store] = {};
}
//query function
var getPage = function (cursorEvent) {
var cursor = cursorEvent.target.result;
if (cursor && (counter < 0 || counter--)) {
if (direction) {
if (counter == pageSize - 1) {
keys[store][direction == "prev" ? first : last] = cursor.key;
}
keys[store][direction == "prev" ? last : first] = cursor.key;
}
page.push(cursor.value);
cursor.continue();
}
}
var transaction = service.db.transaction([store], "readonly");
var objectStore = transaction.objectStore(store);
var rangeStart = null;
if (direction) {
var bound = direction == "prev" ? upperBound : lowerBound;
rangeStart = keys[store].first
? IDBKeyRange.bound(keys[store].first)
: null;
}
var cursor = objectStore.openCursor(rangeStart, direction);
cursor.onsuccess = getPage;
transaction.oncomplete = function () { deferred.resolve(q(page)); }
return deferred.promise;
}
var pageAvailability = function(bound) {
var deferred = $q.defer();
var transaction = service.db.transaction([store], "readonly");
var objectStore = transaction.objectStore(store);
var countRequest = objectStore.count();
cursor.onsuccess = function (response) {
deferred.resolve(response > 0);
}
return deferred.promise;
}
service.prevPage = function (store, pageSize) {
return pageFunction(store, pageSize, "prev");
}
service.hasPrev = function (store) {
return pageAvailability(IDBKeyRange.upperBound(keys[store].last));
}
service.hasNext = function() {
return pageAvailability(IDBKeyRange.lowerBound(keys[store].first));
}
service.nextPage = function(store, pageSize) {
return pageFunction(store, pageSize, "next");
}
service.thisPage = function(store, pageSize) {
return pageFunction(store, pageSize);
}