在 IndexedDB 对象存储块 UI 中插入大量数据

Posted

技术标签:

【中文标题】在 IndexedDB 对象存储块 UI 中插入大量数据【英文标题】:Inserting large quantities in IndexedDB's objectstore blocks UI 【发布时间】:2012-05-15 08:26:19 【问题描述】:

我想在我的 IndexedDB 的对象存储中保存大约 35000 个对象。我正在使用下面的代码插入。

AddListings = function (x2j_list_new, callback)    
    var transaction = db.transaction(["listings"], IDBTransaction.READ_WRITE);
    var count = 0;
    transaction.oncomplete = function (event) 
        if (callback) 
            console.log('x2jShowListing Added ' + count + '/' + x2j_list_new.length);
                callback([count, x2j_list_new.length]);
            
    ;
    transaction.onerror = function (e) 
       console.log("myError: ", e);  
       if (callback) 
          callback(false);
       
    ;
    var store = transaction.objectStore("listings");

    $.each(x2j_list_new, function (index0, item0) 
        var request = store.put(item0);
        request.onsuccess = function (event) 
            count++;
            // event.target.result  
            ;
        );
    );        
;

上面的代码运行良好,但循环和插入超过 35000 个对象会使 UI 无响应约 200 秒。我想也许我可以使用 WebWorkers,但 IndexedDB 在 WebWorkers 中不可用。我试图找到一种批量插入的方法,但找不到。关于如何在不阻塞 UI 的情况下插入大量对象的任何想法?

【问题讨论】:

现在我将数组拆分为 500 个 chunks 并使用 setInterval 而不是 for 循环。现在 UI 的响应比以前好一点。 所以我知道这是旧的,但只是想知道是否有人在 Web 工作者中使用 IndexedDB 的更新,因为它现在受支持? 【参考方案1】:

通过使用回调,你做的一切都是正确的。

Webworker API 尚未被任何主流浏览器实现。有趣的是,它预计是同步的。由于您描述的确切原因,常规 API 是异步的——它不应该阻塞 UI 线程。

使用回调是避免锁定的方法,但是在 35k 个对象时,您会清楚地看到这种范式崩溃了。不幸的是,从我所看到的基准来看,IDB 的性能还不能与 WebSQL 相提并论。

Chrome 的 LevelDB 出现了一些新的实验性后端(FF 是 SQLite),但我认为您的经验证明还有一些改进的余地。

【讨论】:

【参考方案2】:

您在正确的轨道上,但您要求浏览器在有机会完成存储一个对象之前存储 35,000 个对象。这是在开始下一个请求之前异步等待一个请求完成的代码(但使用相同的事务):

    openRequest = window.indexedDB.open("MyDatabase", 1);
    openRequest.onerror = function(event) 
        console.error(event);
    ;
    openRequest.onsuccess = function (event) 
        var db = openRequest.result;
        db.onerror = function(event) 
            // Generic error handler for all errors targeted at this database's requests
            console.error(event.target);
            window.alert("Database error: " + event.target.wePutrrorMessage || event.target.error.name || event.target.error || event.target.errorCode);
        ;
        var transaction = db.transaction('item', "readwrite");
        var itemStore = transaction.objectStore("item");
        putNext();

        function putNext() 
            if (i<items.length) 
                itemStore.put(items[i]).onsuccess = putNext;
                ++i;
             else    // complete
                console.log('populate complete');
                callback();
            
                   
    ;      

【讨论】:

为了确保所有商品都真的在商店里 - 订阅transaction.oncomplete事件,smth like:transaction.oncomplete = callback 我看不到如何确定交易的结束,从交易中获取一个商店,然后添加一条或多条记录...添加所有后如何使交易结束它 ? onsuccess 回调返回后事务是否结束?在这个递归调用中添加了所有条目之后是哪个?我想是的【参考方案3】:

我将数组拆分为 500 个块并使用 setTimeout 而不是 for 循环。现在 UI 的响应比以前好一点

【讨论】:

我不建议从多个事件循环任务中访问 IndexedDB。这种方式的行为很奇怪【参考方案4】:

我的猜测很疯狂,但如果 WebSQL 可从所谓的“后台页面”获得,并且假设前端和后端之间的消息传递带宽不会以相同的方式锁定 UI,那么可能是可以使用带有页内消息的背景页面吗?

【讨论】:

我感觉它是导致阻塞 UI 的 for 循环。我希望有一种方法可以定期 ping 浏览器,这样它就不会认为它卡住了 在传统的 GUI 编程中,您可以检测浏览器何时“空闲”并在大循环中执行另一个步骤。不幸的是,在 javascript 中检测空闲状态并不容易,但有一些黑客可以模拟它。例如***.com/questions/667555/… .

以上是关于在 IndexedDB 对象存储块 UI 中插入大量数据的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地将大文件加载到 IndexedDB 存储中?我的应用程序在超过 100,000 行时崩溃

indexedDB 在概念上与 HTML5 本地存储有何不同?

#yyds干货盘点#聊一聊IndexedDB

vue+elementUi+IndexedDB完整代码浏览器本地存储缓存数据库openaddgetAllopenCursorputdeletewindowobjectStore

我应该只使用IndexedDB还是同时使用IndexedDB和chrome.storage?

IndexedDB 错误:NotFoundError:无法在“IDBDatabase”上执行“事务”:未找到指定的对象存储之一