Database Hierarchy
Oct 11 2018 11:11pm | | Share

Pitfalls of IndexedDB Implementation

By Alex Krasavtsev

Indexed Database API or IndexedDB, is a web browser interface for a transactional client-side database of JSON object collections with indexes. IndexedDB provides you with a convenient way of storing data locally. One of the advantages of IndexedDB is a relatively large storage capacity provided by a browser.

 

I think that the implementation of IndexedDB in a browser is one of the greatest developments for front-end app dev. It provides versatile capabilities to cache data and meaningful ways to access persistent data. If implemented correctly, it may significantly improve the user experience on applications which handle a significant amount of data.

 

Unfortunately, the level of support for IndexedDB varies across different browsers, with Internet Explorer (IE) being the worst one. With this blog post, I want to highlight a few pitfalls of IndexedDB, which hopefully you will find helpful.

 

Pitfall #1: Initialization of IndexedDB database

 

Initialization of IndexedDB looks as following:


dbInitEvent = $window.indexedDB.open('DBName', DBVersion);


Where DBName is a name of a database and DBVersion is a version of a database.

 

You need to make sure that version of the database is an integer value. You can’t use floats or strings.

 

Pitfall #2: You need to use callbacks

 

Most operations with IndexedDB will lock up a database for a certain period of time and you want to make sure you do not attempt to do anything with it during that time. IndexedDB provides callbacks for you to listen for operations to complete.

 

Here is an example of IndexedDb initialization code:


dbInitEvent.onupgradeneeded = function(event) {
  var db = event.target.result;

  db.deleteObjectStore('store-name'); 

  var objectStore = db.createObjectStore('storename', {autoIncrement: true});

  objectStore.transaction.oncomplete = function(event) {
    // Callback to continue operation
  };
};

 

After initialization, IndexedDB will fire the “onupgradeneeded” callback when a local version of a database is different from the version you are trying to initialize. The simplest way to update a database is to erase an existing one and create a new one. This operation may take some time if your existing storage wasn’t empty. Therefore you need to listen for the operation to complete.

 

Pitfall #3: Don’t try to erase a non-existent database

 

In the previous example we used the deleteObjectStore() method. However, the ‘“onupgradeneeded” callback will be triggered for both non-existent databases and databases which need an upgrade. If oldVersion of a database is equal to 0, that means the database doesn’t exist and it is not necessary to erase anything.

 

Here is revised IndexedDB initialization:


dbInitEvent.onupgradeneeded = function(event) {
  var db = event.target.result;

  if (event.oldVersion !== 0) {
    dbInstance.deleteObjectStore('storename');
  }

  var objectStore = dbInstance.createObjectStore('storename', {autoIncrement: true});

  objectStore.transaction.oncomplete = function(event) {
    // Callback to continue operation
  };
};

 

Pitfall #4: UI Blocking operations

 

When saving data into IndexedDB storage, you may be tempted to just loop through the data and add item by item into storage. You may get away with a small amount of data. However, if you have a substantial amount of data, a computer will be completely frozen during such an operation. Instead of adding all records in a loop, you need to add records one by one and watch for completion of the previous addition.

 

Here is how you can implement it:


function addData (dataArray) {
  var transaction = dbInstance.transaction(['storename'], 'readwrite');
  var objectStore = transaction.objectStore('storename');

  var i = 0; 

  addNextItem();

  function addNextItem () {
    if (i < dataArray.length) {
      objectStore.add(dataArray[i]).onsuccess = addNextAccount;

      i++;
    } 
  }
}

 

Pitfall #5: Let a user know you are doing something, but be careful

 

In our use case with 60k of records, it takes up to 12 seconds to add all records into IndexedDb storage. You want to make sure the user is aware that you are updating a database by displaying a spinner or a progress bar.

Progress Bar

However, a UI update in a browser is also a quite an extensive operation. If you are planning to update a progress bar after an addition of each record, the duration of IndexedDB update will increase significantly. Therefore, you need to choose a threshold for a progress bar update. 100 records was the magic number in our case.

 

Pitfall #6: getAll() is not supported by Internet Explorer

 

There is a nice method which allows you to retrieve all records at once from IndexedDB - objectStore.getAll(). Unfortunately, this method is not supported by IE. What you have to do is use a database cursor, to retrieve all necessary records.

 

Here is how you can implement it:


var transaction = dbInstance.transaction(['storename'], 'readwrite');
var objectStore = transaction.objectStore('storename');

var dataArray = [];

var index = objectStore.index('isSoldShipSame');
var cursorRequest = index.openCursor();

cursorRequest.onsuccess = function(event) {
  var cursor = event.target.result;

  if (cursor) {
    dataArray.push(cursor.value);
    cursor.continue();
  }
};

transaction.oncomplete = function() {
  // Callback to continue operation
};

 

Pitfall #7: Debugging IndexedDB in Internet Explorer

 

Internet Explorer doesn’t provide IndexedDB inspection tools inside its developer console. When you see something like this, you may think “How is that possible?”. Error messages, which IE throws in the debugger console are next to meaningless too. However, Microsoft does provide an external package, which you need to include in an iframe on a page, which uses IndexedDB to debug it. Here is a post on the subject on the Microsoft website https://blogs.msdn.microsoft.com/ie/2012/01/25/debugging-indexeddb-applications/. I haven’t tested it and I have gotten away with carefully debugging it in other browsers, and validating support level of every part of functionality on the Mozilla website https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API and carefully testing all functionality in IE.

Browser Compatibility

Conclusion

 

Please, don’t be thrown off by unequal and poor support among browsers. This blog post will help you navigate away from common pitfalls.

 

Please, feel free to share other pitfalls, which you may come across while implementing IndexedDb in your app or website.