Как правильно обрабатывать ошибки в API indexeddb в javascript?

В javascript у меня есть класс для обработки запросов. Я хочу убедиться, что у меня все правильно настроено для обработки ошибок. Я хочу открыть соединение с БД и закрыть его при каждом запросе. У меня есть этот код до сих пор

export default class IndexedDBStorage {

    #name:string;

    constructor(name:string) {
        this.#name = name;
    }

    private async GetDB():Promise<IDBDatabase> {
        return new Promise((resolve, reject) => {

            // https://javascript.info/indexeddb
            const request = window.indexedDB.open(this.#name, 1);

            request.onupgradeneeded = () => {
                //this.#db = request.result;
                if (!request.result.objectStoreNames.contains(this.#name)) {
                    request.result.createObjectStore(this.#name, {keyPath: 'id', autoIncrement:true});
                }
            };

            request.onerror = () => {
                reject("Why didn't you allow my web app to use IndexedDB?! " + request.error?.code);
            };

            request.onsuccess = () => {
                //request.result.onerror = () => {
                    // Generic error handler for all errors targeted at this database's requests!
                //    reject("Database error: " + request.error?.code);
                //};

                resolve(request.result);
            };
        });
    }

    async GetAllItems<T>():Promise<Array<T>> {
        return new Promise((resolve, reject) => {
            this.GetDB().then(db => {
                const transaction = db.transaction(this.#name);
                const store = transaction.objectStore(this.#name);
                const datarequest = store.getAll();
                db.close();
                datarequest.onsuccess = function() {
                    resolve(datarequest.result);
                };
                datarequest.onerror = function() {
                    reject("Error " + datarequest.error);
                }; 
            }).catch(err => {
                console.error(err);
            });
        });
    }
}

Также хотелось узнать, чем отличается эта часть внутри функции GetDB. Это событие onerror самой базы данных, которое настраивается в событии onsuccess.

            //request.result.onerror = () => {
                // Generic error handler for all errors targeted at this database's requests!
            //    reject("Database error: " + request.error?.code);
            //};

И эта часть

            datarequest.onerror = function() {
                reject("Error " + datarequest.error);
            }; 

?

Спасибо

Обновлено:

export default class IndexedDBStorage {

    #name:string;

    constructor(name:string) {
        this.#name = name;
    }

    private async GetDB():Promise<IDBDatabase> {
        return new Promise((resolve, reject) => {

            const request = window.indexedDB.open(this.#name, 1);

            request.onerror = (event: Event) => {
                // this function catches all errors
                // all errors in database, transaction or request levels should be caught and handled there
                const errorEvent = event as Event & {error:string};
                console.error(errorEvent.error);
                alert(errorEvent.error);
                reject(errorEvent.error);
            };

            request.onblocked = function () {
                // this event shouldn't trigger if we handle onversionchange correctly
                // it means that there's another open connection to the same database
                // and it wasn't closed after db.onversionchange triggered for it
                const message = 'Database is currently blocked, page needs to reload, click ok to reload.';
                alert(message);
                window.location.reload();
                //console.info(message);
                //reject(message);
            };

            request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
                const db = request.result;
                console.info('idb onupgradeneeded firing');
                switch(event.oldVersion) { // existing db version
                    case 0:
                      // version 0 means that the client had no database
                      // perform initialization
                      console.info('Database currently at version 0 which means that the client had no database');
                      console.info(`Upgrading to version ${db.version}`);
                      request.result.createObjectStore(this.#name, {keyPath: 'id', autoIncrement:true});
                    case 1:
                      // client had version 1
                      // update
                      console.info('Database currently at version 1 which means that the database already exists');
                }
            };

            request.onsuccess = () => {
                const db = request.result;
                db.onversionchange = function() {
                    db.close();
                    const message = "Database is outdated, page needs to reload, click ok to reload.";
                    alert(message);
                    window.location.reload();
                };
                resolve(db);
            };
        });
    }

    async GetAllItems<T>():Promise<Array<T>> {
        return new Promise((resolve, reject) => {
            this.GetDB().then(db => {
                const transaction = db.transaction(this.#name);
                const store = transaction.objectStore(this.#name);
                const datarequest = store.getAll();
                db.close();
                datarequest.onsuccess = function() {
                    resolve(datarequest.result);
                };
            }).catch(err => {
                reject(err);
            });
        });
    }
}

Избегайте антипаттерна конструктора обещаний ! Создайте new Promise только для каждого запроса, но в противном случае используйте цепочку промисов.

Bergi 05.04.2023 04:07

На самом деле это хороший пример проблем с этим «антипаттерном конструктора обещаний»: GetAllItems никогда не урегулируется (ни разрешится, ни отклонится), если this.GetDB() отклонит.

kca 05.04.2023 18:36

@Bergi Как я могу это исправить? Я не очень понимаю из вашей ссылки, как это исправить.

omega 06.04.2023 22:48

В основном return this.getDb().then(db => { return new Promise((resolve, reject) => { … }); }).catch(…). Хотя вам, вероятно, следует удалить .catch(console.error) , и если getDb() возвращает базу данных, которую всегда нужно закрывать, вы можете использовать шаблон disposer.

Bergi 06.04.2023 23:31
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
4
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  • запросы могут ошибаться, при ошибках запроса он получает свойство error со значением
  • транзакции могут ошибаться, но ошибка будет доступна только из одного из ошибочных запросов в транзакции
  • нет большой разницы между запросом на открытие БД и запросом на получение/помещение/добавление/и т.д. технически один тип IDBOpenRequest, а другой тип IDBRequest, я думаю, что IDBOpenRequest расширяет IDBRequest
  • при обработке ошибки транзакции доступ к ошибке осуществляется через событие, потому что event.target будет указывать на ошибочный запрос, поэтому event.target.error, также известный как request.error, является объектом ошибки, где событие — это просто событие не сама ошибка
  • вы можете обернуть IDBOpenRequest в обещание, и вы можете обернуть запрос или транзакцию в обещание
  • обычно избегайте оборачивать запросы в промисы, за исключением открытого запроса, всегда оборачивайте внешнюю транзакцию из-за возможных проблем с микрозадачами промисов и из-за того, что транзакции indexeddb истекают в цикле событий
  • поскольку вы перехватываете отказ от обещания в GetAllItems, а обратный вызов, который вы используете для перехвата, является функцией void, вы эффективно подавляете ошибку и возвращаете обещание, которое всегда разрешается либо в массив, либо в неопределенное
  • вы не рассматриваете заблокированное событие, которое может произойти в открытом запросе, где, по сути, обещание остается неопределенным на неопределенный срок (пока база данных не будет разблокирована из-за завершения параллельных транзакций изменения версии), поэтому этот код не всегда будет работать так хорошо
  • я предлагаю не прослушивать ошибки, которые всплывают в базе данных, всегда прослушивать ошибки на уровне запроса (за исключением случаев, когда транзакция обертывается обещанием, в этом случае прослушивайте уровень транзакции, но получайте доступ к ошибке через event.target.error, который указывает на запрос в ошибочной транзакции), я настоятельно рекомендую просто полностью игнорировать всплывающую функцию indexeddb.

Другие вопросы по теме