在异步函数中等待索引数据库事件



我正在尝试从异步函数返回一个自定义对象,该函数用作使用 indexdb 放置的包装器。

使用承诺这很容易。 但是,使用 async/await 变得更具挑战性...

const set = async (storeName, key, value) => {

if (!db)
throw new Error("no db!");
try {
const result = {};
let tx = db.transaction(storeName, "readwrite");
let store = tx.objectStore(storeName);
let r = store.put({ data: key, value: value });
console.log(r);
r.onsuccess = async () => {
console.log('onsuccess');
result.something = true;
}
r.onerror = async () => {
console.log('onerror');
result.something = false;
}
await r.transaction.complete;  // ok... this don't work
// how can I await until onsuccess or onerror runs?
return result;
} catch (error) {
console.log(error);
}
}

想法是返回一个组合对象...但是,我所有的尝试都失败了,因为返回结果后成功运行。

我用谷歌搜索了很多,但找不到一种方法来正确等待成功/错误事件。

我知道返回承诺更容易,因为 solve(result( 会结束返回我想要的东西......但是我正在尝试学习使用async/await制作相同的代码

非常感谢

试试这个:

function set(db, storeName, key, value) {
return new Promise((resolve, reject) => {
let result;
const tx = db.transaction(storeName, 'readwrite');
tx.oncomplete = _ => resolve(result);
tx.onerror = event => reject(event.target.error);
const store = tx.objectStore(storeName);
const request = store.put({data: key, value: value});
request.onsuccess = _ => result = request.result;
});
}
async function callIt() {
const db = ...;
const result = await set(db, storeName, key, value);
console.log(result);
}

编辑,由于您坚持对 set 函数使用异步限定符,因此您可以改为执行此操作。请注意,我觉得这很愚蠢:

async function set(db, storeName, key, value) {
// Wrap the code that uses indexedDB in a promise because that is 
// the only way to use indexedDB together with promises and 
// async/await syntax. Note this syntax is much less preferred than 
// using the promise-returning function pattern I used in the previous 
// section of this answer.
const promise = new Promise((resolve, reject) => {
let result;
const tx = db.transaction(storeName, 'readwrite');
tx.oncomplete = _ => resolve(result);
tx.onerror = event => reject(event.target.error);
const store = tx.objectStore(storeName);
const request = store.put({data: key, value: value});
request.onsuccess = _ => result = request.result;
});
// We have executed the promise, but have not awaited it yet. So now we 
// await it. We can use try/catch here too, if we want, because the 
// await will translate the promise rejection into an exception. Of course, 
// this is also rather silly because we are doing the same thing as just 
// allowing an uncaught exception to exit the function early.
let result;
try {
result = await promise;
} catch(error) {
console.log(error);
return;
}
// Now do something with the result
console.debug('The result is', result);
}

最终,您将最终将 IDB 包装在一个承诺朋友库中,但对于您的特定需求,您可以使用这样的东西:

function promiseForTransaction(tx) {
return new Promise((resolve, reject) => {
tx.oncomplete = e => resolve();
tx.onabort = e => reject(tx.error);
});
}

然后在您的代码中,您可以编写如下内容:

await promiseForTransaction(r.tx);

。这将等到事务完成,如果它中止,则会引发异常。(请注意,这需要调用帮助程序 在事务可能完成/中止之前,因为 如果事件已经触发,它永远不会解决(

我现在无法确认,但我认为它应该是await tx.complete而不是await r.transaction.complete;

但是,即使 API 不直接支持 Promise,一个通用的解决方案是围绕onsuccessonerror进行new Promise,并使用await等待该 Promise 解析,然后在您的onsuccessonerror中调用resolve函数:

const set = async (storeName, key, value) => {

if (!db)
throw new Error("no db!");
try {
const result = {};
let tx = db.transaction(storeName, "readwrite");
let store = tx.objectStore(storeName);
let r = store.put({
data: key,
value: value
});
console.log(r);
await new Promise((resolve, reject) => {
r.onsuccess = () => {
console.log('onsuccess');
result.something = true;
resolve()
}
r.onerror = () => {
console.log('onerror');
result.something = false;
// I assume you want to resolve the promise even if you get an error
resolve()
}
})
return result;
} catch (error) {
console.log(error);
}
}

我会进一步将其更改为:

try {
await new Promise((resolve, reject) => {
r.onsuccess = resolve
r.onerror = reject
})
console.log('success');
result.something = true;
} catch(err) {
console.log('error');
result.something = false;
}

最新更新