如何在javascript中正确处理indexeddb API中的错误?

nc1teljy  于 2023-04-10  发布在  IndexedDB
关注(0)|答案(1)|浏览(312)

在javascript中,我这里有一个类来处理请求。我想确保我已经把所有的错误处理设置好了。我想打开到db的连接,并在每个请求时关闭它。到目前为止我有这样的代码

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函数内部的这部分有什么区别。这是db本身的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.log(message);
                //reject(message);
            };

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

azpvetkf1#

  • 请求可能出错,当请求出错时,它将获取一个带有值的error属性
  • 事务可能出错,但只能从事务中出错的请求之一访问错误
  • 打开数据库的请求和get/put/add/etc.的请求之间没有太大的区别。技术上一个是IDBOpenRequest类型,一个是IDBRequest类型,我认为IDBOpenRequest扩展了IDBRequest
  • 如果处理事务错误,则通过事件访问错误,因为event.target将指向出错的请求,因此event.target.error(也称为request.error)是错误对象,其中event只是事件而不是错误本身
  • 您可以将IDBOpenRequest Package 在Promise中,也可以将请求或事务 Package 在Promise中
  • 通常避免将请求 Package 在promise中,除了open请求,总是 Package 外部事务,因为promise微任务可能存在问题,以及indexeddb事务如何在事件循环中超时
  • 因为您在GetAllItems中捕获了promise拒绝,并且用于该catch的回调是一个void函数,所以您有效地抑制了错误并返回了始终解析为数组或undefined的promise
  • 您没有考虑可能在open请求中发生的阻塞事件,其中promise基本上无限期地处于未解决状态(直到数据库由于并发版本更改事务完成而解除阻塞),因此此代码并不总是工作得很好
  • 我建议不要监听冒泡到数据库的错误,总是在请求级别监听错误(除了在promise中 Package 事务时,在这种情况下在事务级别监听,但通过event.target.error访问错误,它指向出错的事务中的请求),我强烈建议完全忽略indexeddb的冒泡功能

相关问题