找到你要的答案

Q:Getting a page of results from IndexedDb using cursor

Q:得到一个页面从IndexedDB使用游标的结果

I'm trying to learn how to use IndexedDb and my next step is getting a page of results from a store. My strategy is to store the last key retrieved for the page in the service and use it to open the cursor using that key as the lower bound on the next request. Here is the function as I originally defined it:

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;
}

If I tried to use this function with only one item in the store, I ran into two problems:

  1. The continue function would throw an error (so I used a try/catch, resolving the array of values in the catch block)
  2. The cursor would return the same value, pageSize times (so I tried checking if the primary key in the current loop iteration matched the last one)

This still isn't working, though. There are now two items in the store, and if I call this function, it gets the first item, and then throws an error saying the cursor is either iterating or past its end.

Am I missing something about how this is supposed to work? I would just use getAll, but this is for a Cordova application and that method is not available. How can I just grab a certain number of results?

我想学习如何使用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. The continue function would throw an error (so I used a try/catch, resolving the array of values in the catch block)
  2. The cursor would return the same value, pageSize times (so I tried checking if the primary key in the current loop iteration matched the last one)

这仍然是行不通的,虽然。现在商店里的两个项目,如果我调用这个函数,它的第一个项目,然后抛出一个错误说光标是迭代或过去的结束。

我错过了什么,这应该是如何工作?我只会用得到,但这是一个科尔多瓦的应用,方法是不可用的。我怎么才能抢到一定数量的结果呢?

answer1: 回答1:

I figured it out. The specification doesn't make it totally obvious, but the onsuccess event handler is called after calling cursor.continue(), so there is no need for an explicit loop. The fixed method looks like this:

 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);
}

我想通了。规范并不能使它完全明显,但会在事件处理程序中调用游标后调用。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);
}
javascript  indexeddb