返回标准for循环中异步调用的响应

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

阅读了Felix Kling的How do I return the response from an asynchronous call?之后,我仍然对如何从异步回调返回值感到困惑。

我的目标:将静态图像转换为base64 once,并将该图像存储在indexDB中,直到indexDB抛出某种存储错误。

我正在使用此异步idb npm模块

// init the idb store
const initIDB = async () => {

  const db = await openDB('db', 1, {
    upgrade(db) {
      db.createObjectStore('tempStore', { keyPath: 'id', autoIncrement: true });
    },
  });
  const tx = db.transaction('tempStore', 'readwrite');
  await overloadIDB(tx.store);
  await tx.done;


  return true;
};
// random number generator
const getRandomArbitrary = (min, max) => Math.random() * (max - min) + min;

// function will overload the idb
const overloadIDB = async (store) => {
  const imgurl = "someLocalImage.png";
  const promises = [];
  return toDataURL(imgurl, async (s) => {
    for (let i = 0; i < 10; i++) {
      if (i > 0 && i % 100 === 0) console.log('A set done');
      try {
        const num = Math.round(getRandomArbitrary(1, 1000000));
        const data = {
          id: num,
          img: s,
        };
        store.add(data);
      } catch (e) {
        console.log(e.toString());
        console.dir(e);
        break;
      }
    }
    console.log('Done');
  });
};

// convert image to base64
const toDataURL = (url, callback) => {
  const xhr = new XMLHttpRequest();
  xhr.onload = () => {
    const reader = new FileReader();
    reader.onloadend = () => {
      callback(reader.result);
    };
    reader.readAsDataURL(xhr.response);
  };
  xhr.open('GET', url);
  xhr.responseType = 'blob';
  xhr.send();
};

理想情况下,我想从toDataURL's回调函数返回该值,并在for循环中使用该结果,但由于异步行为,我总是得到undefined,这是有意义的。

以上代码无法多次执行事务store.add(data),并且在执行i = 0时失败。

我曾尝试像这样用toDataURL包装new Promise(resolve, reject)

const toDataURL = (url, callback) => new Promise((resolve, reject) => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.responseType = 'blob';
  xhr.onload = () => {
    const reader = new FileReader();
    reader.onloadend = () => {
      resolve(callback(reader.result));
    };
    reader.readAsDataURL(xhr.response);
  };
  xhr.send();
});

然后使用Promise.all像这样解析商店数组

const overloadIDB = async (store) => {
  const imgurl = 'someLocalImage.png';
  const promises = [];
  return toDataURL(imgurl, async (s) => {
    console.log('s :', s);
    for (let i = 0; i < 10; i++) {
      if (i > 0 && i % 100 === 0) console.log('A set done');
      try {
        const num = Math.round(getRandomArbitrary(1, 1000000));
        const data = {
          id: num,
          img: s,
        };
        promises.push(store.add(data));
      } catch (e) {
        console.log(e.toString());
        console.dir(e);
        break;
      }
    }
    await Promise.all(promises);
    console.log('Done');
  });
};

但返回错误Failed to execute 'add' on 'IDBObjectStore': The transaction has finished.

[我认为我的方法有缺陷,但不确定如何解决。任何人都可以指出一些解决方案吗?

javascript asynchronous callback indexeddb
1个回答
0
投票

您不能在indexedDB操作的中间执行异步操作。完全执行获取,然后连接,创建事务并存储结果。

© www.soinside.com 2019 - 2024. All rights reserved.