使用游标从 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;
}

如果我尝试对商店中的一件商品使用此功能,我 运行 会遇到两个问题:

  1. continue 函数会抛出错误(所以我使用了 try/catch,解析 catch 块中的值数组)
  2. 光标会 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);
}