После прочтения Как вернуть ответ от асинхронного вызова? от Феликса Клинга, я все еще не понимаю, как я могу вернуть значение из асинхронного обратного вызова.
Моя цель: преобразовать статическое изображение в base64 один раз и сохранить это изображение в 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.
На данный момент я думаю, что мой подход неверен, но я не уверен, как я могу это исправить. Кто-нибудь может указать на какое-то решение, пожалуйста?