使用游标从IndexedDb获取结果页面

时间:2015-10-07 12:28:45

标签: javascript indexeddb

我正在尝试学习如何使用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. 游标将返回相同的值pageSize次(所以我尝试检查当前循环迭代中的主键是否与最后一个匹配)
  3. 但是,这仍然不起作用。商店现在有两个项目,如果我调用这个函数,它会得到第一个项目,然后抛出一个错误,说光标正在迭代或超过它的结束。

    我错过了一些关于它应该如何工作的内容吗?我只想使用getAll,但这适用于Cordova应用程序,并且该方法不可用。我怎样才能获得一定数量的结果?

1 个答案:

答案 0 :(得分:0)

我明白了。规范并没有完全明显,但在调用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);
}