2012-05-06 14 views
15

私のIndexedDBのオブジェクトストアに〜35000個のオブジェクトを保存します。私は挿入するコードを以下に使用しています。IndexedDBのオブジェクトストアブロックに大量の挿入UI

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個のオブジェクトをループし、過挿入する〜200秒間、UIが応答しなくなります。おそらく私はWebWorkersを使うことができると思っていましたが、IndexedDBはWebWorkersでは利用できません。一括挿入する方法を見つけようとしましたが見つかりませんでした。 UIをブロックせずに大量のオブジェクトを挿入する方法のアイデアですか?

+1

は(今私は[チャンク]で配列を分割していますについてhttp://stackoverflow.com/questions/ 8495687/split-array-into-chunks)を500に設定し、[setInterval](http://www.kryogenix.org/days/2009/07/03/not-blocking-the-ui-in-tight-javascript-ループ)の代わりに使用します。今やUIはこれまでよりも少し良く応答します。 – surya

答えて

28

あなたは正しい道を歩いていますが、35000個のオブジェクトを保存する前にブラウザに保存するように求めています。ここでは一つのリクエストは次の(しかし、同じトランザクションを使用して)を開始する前に終了するのを待って非同期コードです:

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(); 
      } 
     }   
    };  
+0

興味深い提案。誰かがこれが達成するパフォーマンスの向上に関するベンチマークを実行していますか? –

+0

ストア内のすべてのアイテムが本当に** **本当に**であることを確認するには、 'transaction.oncomplete'イベントを購読してください:' transaction.oncomplete = callback' – Kiril

+0

トランザクションの終了を判断する方法がわかりません1つはトランザクションからストアを取得し、1つ以上のレコードを追加します...トランザクションをすべて追加したらどうすれば終了できますか? onsuccessコールバックが返った後でトランザクションは終了しますか?この再帰呼び出しですべてのエントリが追加された後はどれですか?そう思う – lisak

0

コールバックを使用して、すべてのことを正しくやっています。

Webworker APIは、主要なブラウザではまだ実装されていません。興味深いことに、同期的であることが期待されます。通常のAPIはあなたが記述した正確な理由で非同期です。UIスレッドをブロックすることは想定されていません。

コールバックの使用はロックアップを回避する方法ですが、35kオブジェクトではこのパラダイムが壊れていることがはっきりしています。残念ながら、私が見たベンチマークからIDBのパフォーマンスはWebSQLと同等レベルにはありません。

ChromeのLevelDBでは、いくつかの新しい実験的バックエンド(FFはSQLite)がありましたが、改善の余地があることが実感できたと思います。

0

WebSQLが「バックグラウンドページ」として知られており、フロントページとバックページの間のメッセージングの帯域幅が同じ方法でUIをロックしていないと仮定すると、ページ内メッセージを含む背景ページを利用することができるだろうか?

+0

私はブロックUIを引き起こしているforループを感じています。私は定期的な間隔でブラウザにpingする方法があったので、それが固まっているとは思わない。 – surya

+0

伝統的なGUIプログラミングでは、ブラウザが "アイドル"であることを検出し、大きな不具合のループで別のステップを実行する。残念ながら、アイドル状態を検出することはjavascriptでは容易ではありませんが、それをシミュレートするためのハックがあります。例えばhttp://stackoverflow.com/questions/667555/detecting-idle-time-in-javascript-elegantly。 –

0

私は500の塊で配列を分割し、forループの代わりにsetTimeoutを使用しています。 UIが以前よりも少し上手く対応しています

+0

複数のイベントループタスクからIndexedDBにアクセスすることはお勧めしません。これはかなり奇妙なこのように動作します – lisak

関連する問題