当我使用 google chrome 浏览器在 indexeddb 中进行页面查询时,如下所示:
export async function getPage<T>(page: number, pageSize: number): Promise<T[]> {
let transaction = (await db).transaction(["prompt"], "readonly");
let store = transaction.objectStore("prompt");
const cursor = await store.index("promptIdIndex").openCursor(null,'next');
let offset = (page - 1) * pageSize;
const data: T[] = [];
while (cursor && offset > 0) {
if(cursor && cursor.key){
cursor.advance(offset);
offset -= cursor.key as number;
}
}
for (let i = 0; cursor && i < pageSize; i++) {
if(cursor && cursor.key){
data.push(cursor.value);
cursor.continue();
}
}
return data;
}
控制台显示错误:
caught (in promise) DOMException: Failed to execute 'continue' on 'IDBCursor': The cursor is being iterated or has iterated past its end.
我应该怎么做才能解决这个问题?我尝试添加光标边缘条件。看来还是不行。这是完整的打字稿文件:
import { openDB, DBSchema } from 'idb';
interface GenieDB {
prompt: {
name: string;
id: number;
};
}
export interface Prompt {
id: number;
name: string;
}
const db = openDB<GenieDB>('genie', 1, {
upgrade(db) {
const promptStore = db.createObjectStore('prompt', {
keyPath: 'id',
autoIncrement: true,
});
promptStore.createIndex("promptIdIndex", "id", { unique: true });
},
});
export async function getPage<T>(page: number, pageSize: number): Promise<T[]> {
let transaction = (await db).transaction(["prompt"], "readonly");
let store = transaction.objectStore("prompt");
const cursor = await store.index("promptIdIndex").openCursor(null,'next');
let offset = (page - 1) * pageSize;
const data: T[] = [];
while (cursor && offset > 0) {
if(cursor && cursor.key){
cursor.advance(offset);
offset -= cursor.key as number;
}
}
for (let i = 0; cursor && i < pageSize; i++) {
if(cursor && cursor.key){
data.push(cursor.value);
cursor.continue();
}
}
return data;
}
我尝试添加此条件来检查光标是否可以继续:
if(cursor && cursor.value && cursor.continue){
data.push(cursor.value);
debugger
cursor.continue();
}
仍然无法工作。
您在同步循环中调用
cursor.advance()
和 cursor.continue()
,而不等待这些异步请求实际完成。如果您展开 while
循环,这就像调用 cursor.advance(offset); cursor.advance(offset);
一样,它会给您带来错误 - 第一个调用要求光标异步关闭并迭代,然后第二个调用会抛出异常,让您知道它没有还没完成。
不清楚的是,您是否已经在 IndexedDB 周围使用异步包装器,因为您调用
await ...openCursor(null,'next');
,即使 IndexedDB 方法 不 本机返回可等待的 Promise。如果您已经在使用包装器,请查看包装器的文档,其中解释了如何 await
advance()
和 continue()
调用。
如果您尚未使用包装器,而是直接使用低级 API,请考虑这样的帮助器:
function promiseForRequest(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => { resolve(request.result); };
request.onerror = () => { reject(request.error); };
});
}
然后你需要修改你的代码,例如:
let cursor = await promiseForRequest(store.index("promptIdIndex").openCursor(null,'next'));
和:
cursor = await promiseForRequest(cursor.advance(offset));
和:
cursor = await promiseForRequest(cursor.continue());
Joshua Bell 的推理和解释是正确的,但建议的代码将不起作用,因为
cursor.continue()
返回 undefined
,而不是适合 IDBRequest
的 promiseForRequest
对象。
查看
continue()
方法的 MDN 示例,您可以看到由 success
返回的 IDBRequest
对象的 openCursor()
事件也会在 continue()
调用时触发。因此,您可以执行以下操作:
// Helper from Joshua Bell's answer
function promiseForRequest(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => { resolve(request.result); };
request.onerror = () => { reject(request.error); };
});
}
// Hold reference to the cursor request, since its `success` event is triggered when we iterate through the cursor
const cursorReq = store.index("promptIdIndex").openCursor(null,'next');
let cursor = await promiseForRequest(cursorReq);
while (cursor) {
// ... use `cursor`
cursor.continue();
await promiseForRequest(cursorReq);
}