IndexedDB

IndexedDB was introduced by Oracle and became popular very quickly. It's a Not Only SQL (NoSQL) database. The IndexedDB API is a more capable and far more complex API. IndexedDB has the following significant benefits:

  • It improves the responsiveness and speed of web programs by minimizing the number of HTTP requests
  • It provides more space for data without Web Storage limits
  • It provides the ability to work offline
  • A NoSQL database helps you work directly with Dart and JavaScript objects
  • It allows fast indexing, object searching, and granular locking per transaction
  • It supports synchronous and asynchronous APIs

One of the major disadvantages can be the difficulty in understanding it if you are coming from the world of rational databases. In IndexedDB, we can store a large amount of structured data, images, arrays, and whole objects; you just need to index them with a key. It follows the same origin policy, so we cannot access data across different domains. If you still use Web SQL database with your products, it's time to migrate to IndexedDB because the Web SQL database was deprecated by World Wide Web Consortium (W3C) in November 2010.

Note

IndexedDB is an indexed table system.

IndexedDB doesn't have any limits on a single database item's size, but it may impose a limit on each database's total items. We will use the asynchronous API because it works in most scenarios, including Web Workers. IndexedDB is a real database; therefore, before we use it, we need to specify a database schema, open a connection, and start using it to retrieve and update data within transactions. In this case, it gets very close to the Web SQL solution but is much simpler. Let's take a look at how we can use our example with IndexedDB. We will use the dart:indexed_db package from the Dart SDK to work with IndexedDB. You can make a copy of the project from the Web SQL section, rename it shopping_cart_indexed_db, and use IndexedDBStorageManager instead of WebSQLStorageManager. The code is as follows:

abstract class StorageManager {
  factory StorageManager() {
    if (IndexedDBStorageManager.supported) {
      return new IndexedDBStorageManager();
    } else if (WebStorageManager.supported) {
      return new WebStorageManager();
    } else {
      return new CookieStorageManager();
    }
  }
  
  Future<String> getItem(key);
  Future setItem(key, value);
  Future removeItem(key);
}

The preceding code shows the IndexedDBStorageManager class. We constructed a special _getDatabase method to retrieve an instance of the Database class. As we mentioned earlier, before we use IndexedDB, we need to open the IndexedDB database. In the following code, we use the window.indexedDB.open method to open our database. Next, we need to check whether the store exists in an objectStoreNames array of the database. If it doesn't exist, we must close the database and open it again with a higher version number. Because this process is asynchronous, we create a new instance of the store object inside the onUpgradeNeeded listener. Each manipulation of the objects of the database happens inside a transaction. So, we will create a new transaction every time and return the ObjectStore instance in the startTransaction method. We will return the value of ObjectStore via the getObject method. To set an item in the database, we use the put method of ObjectStore. To remove the object from the store, just call the delete method, as shown in the following code:

class IndexedDBStorageManager implements StorageManager {
  
  Database _database;
  
  static const SHOPPING = "SHOPPING";
  static const PRODUCT = "PRODUCT";
  static const TRANS_MODE = "readwrite";
  Future _getDatabase(String dbName, String storeName) {
    if (_database == null) {

      return window.indexedDB.open(dbName).then((Database d) {
        _database = d;
        if (!_database.objectStoreNames.contains(storeName)) {
          _database.close();
          return window.indexedDB.open(dbName, 
              version: (d.version as int) + 1, 
              onUpgradeNeeded: (e) {
            Database d = e.target.result;
            d.createObjectStore(storeName);
          }).then((Database d) {
            _database = d;
            return _database;
          });
        }
        return _database;
      });
    } else {
      return new Future.sync(() => _database);
    }
  }
  Future
  <ObjectStore> startTransaction(String storeName) {
    return _getDatabase(SHOPPING, PRODUCT)
     .then((Database database) {
      Transaction transaction =  
        _database.transactionStore(storeName, TRANS_MODE);
      return transaction.objectStore(storeName);
    });
  }
  Future
  <String> getItem(key) {
    return new Future.sync(() {
      return startTransaction(PRODUCT).then((ObjectStore store) {
        return store.getObject(key);
      });
    });
  }
  Future 
  setItem(key, value) {
    return new Future.sync(() {
      return startTransaction(PRODUCT).then((ObjectStore store) {
        return store.put(value, key);
      });
    });
  }
  Future
  removeItem(key) {
    return new Future.sync(() {
      return startTransaction(PRODUCT).then((ObjectStore store) {
        return store.delete(key);
      });
    });
  }
}

That's it. We can perform all manipulations on the data within ObjectStore. The fact that the ObjectStore class instance was returned via a Transaction class indicates that all steps in the original one will be surrounded by a transaction. Let's expand the IndexedDB tree item in the Resources tab to see the SHOPPING database.

IndexedDB

The version number of the database is 2. Now, choose the PRODUCT tree item and you will see that the same name contains our data.

IndexedDB

When compared to Web SQL, IndexedDB is more simple and flexible. It uses indexes to access objects in the database within transactions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.30.178