捕获(承诺中)DOMException:无法在“IDBCursor”上执行“继续”:光标正在迭代或已迭代超过其末尾

问题描述 投票:0回答:2

当我使用 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();
        }

仍然无法工作。

typescript indexeddb
2个回答
1
投票

您在同步循环中调用

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

0
投票

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.