简体   繁体   English

等待异步功能中的indexdb事件

[英]await for indexdb event in async function

I'm trying to return a custom object from a async function that works as wrapper for a put using indexdb. 我试图从异步函数返回一个自定义对象,该异步函数用作使用indexdb的put的包装器。

Using Promises this is easy. 使用Promises,这很容易。 However, using async/await became more challenging... 但是,使用异步/等待变得更具挑战性...

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

The ideia is to return a composed object... however all my attemps fails as onsuccess runs after returning the result. 想法是返回一个组合对象……但是由于返回成功后成功运行,我的所有尝试都失败了。

I googled a lot and could't find a way to proper await for onsuccess/onerror events. 我在Google上搜索了很多,却找不到适当的方法来等待成功/错误事件。

I know that returning a Promise is more easy as resolve(result) would end returning what I want... but i'm trying to learn to make same code using async/await . 我知道返回Promise更容易,因为resolve(result)最终将返回我想要的东西……但是我正在尝试学习使用async / await编写相同的代码

Thank you so much, 非常感谢,

I can't confirm it right now but I think it should be await tx.complete instead of await r.transaction.complete; 我目前无法确认,但是我认为应该await tx.complete而不是await r.transaction.complete; .

But a general solution that would work even if the API would not support Promises directly would be to wrap a new Promise around the onsuccess and onerror and use await to wait for that Promise to resolve, and in your onsuccess and onerror you then call the resolve function: 但是,即使API不支持的承诺,将工作的通用解决方案,直接将包装一个new Promise周围onsuccessonerror和使用await ,等待这个承诺来解决,并在你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);
  }
}

I would furhter change it to: 我会进一步将其更改为:

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

Try this: 尝试这个:

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

Edit, since you insist on using the async qualifier for the set function, you can do this instead. 编辑,因为您坚持对set函数使用异步限定符,所以可以改为执行此操作。 Please note I find this pretty silly: 请注意,我觉得这很愚蠢:

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

Ultimately you'll end up wrapping IDB in a promise-friend library, but for your specific need, you could use something like this: 最终,您最终将把IDB封装在一个promise-friend库中,但是对于您的特定需求,您可以使用以下方法:

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

And then in your code you can write things such as: 然后,您可以在代码中编写以下内容:

await promiseForTransaction(r.tx);

... which will wait until the transaction completes, and throw an exception if it aborts. ...,它将等待事务完成,如果中止则抛出异常。 (Note that this requires calling the helper before the transaction could possibly have completed/aborted, since it won't ever resolve if the events have already fired) (请注意,这需要在事务可能完成/中止之前调用帮助程序,因为如果事件已经触发,它将永远无法解决)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM