等待异步功能中的indexdb事件

时间:2018-10-16 13:34:37

标签: javascript asynchronous async-await indexeddb

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

使用Promise很容易。 但是,使用异步/等待变得更具挑战性……

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

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

我在Google上搜索了很多,却找不到适当的方法来等待成功/错误事件。

我知道返回Promise更容易,因为resolve(result)最终会返回我想要的东西...但是我正在尝试学习使用async / await编写相同的代码。< / p>

非常感谢您

3 个答案:

答案 0 :(得分:0)

我目前无法确认,但我认为应该是<!-- checkbox --> <template> <div class="checkbox-part"> <input class="checkbox-part-input" type="checkbox" :name="name" :id="id" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" > <label class="checkbox-part-label" :for="name" :class="{ 'checkbox-part-label--checked': checked }" > <slot name="label"></slot> </label> <!-- removed for brevity --> </div> </template> <script> export default { model: { prop: 'checked', event: 'change' }, props: { checked: { type: Boolean, }, name: { type: String, required: true }, id: { type: String, required: true } } } </script> <!--- parent component using the one --> <template> <!-- removed for brevity --> <!-- ... --> <div class="expandable-category-part-social-section"> <checkbox-part v-model="isSocialIntegrationEnabled" :id="title + 'social-media'" :name="title + 'social-media'" > <template slot="label"> <div class="checkbox-part-label-text">Final text comes here...</div> </template> </checkbox-part> </div> <!-- ... --> </template>而不是await tx.complete

但是,即使API不直接支持Promises,仍然可行的通用解决方案是将await r.transaction.complete;包裹在new Promiseonsuccess周围,并使用onerror等待该Promise解决,然后在awaitonsuccess中调用onerror函数:

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

答案 1 :(得分:0)

尝试一下:

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

答案 2 :(得分:0)

最终,您最终将把IDB封装在一个promise-friend库中,但是对于您的特定需求,您可以使用以下方法:

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

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

await promiseForTransaction(r.tx);

...,它将等待事务完成,如果中止则抛出异常。 (请注意,这需要致电帮助程序 在交易可能已经完成/中止之前,因为 如果事件已经触发,它将永远无法解决)