locked
IndexedDB and Promises

    Question

  • if (window.indexedDB == null) window.indexedDB = window.msIndexedDB;
    
      init = function() {
        return new WinJS.Promise(function(complete, error, progress) {
          var opening;
          opening = window.indexedDB.open("kids", 1);
          opening.onupgradeneeded = function(event) {
            return setupDatabase(event.target.transaction, complete, error, progress);
          };
          opening.onsuccess = function(event) {
            var db;
            db = event.target.result;
            return mixinObjectStores(db, complete, error, progress);
          };
          return opening.onerror = error;
        });
      };
    
      setupDatabase = function(tx, complete, error, progress) {
        var kids;
        tx.oncomplete = function(event) {
          progress("Database setup complete");
          mixinObjectStores(tx.db, complete, error, progress);
        };
        tx.onerror = error;
        kids = tx.db.createObjectStore('kids', {
          keyPath: 'id',
          autoIncrement: true
        });
        kids.createIndex('byName', 'name');
      };

    Given this code I wonder if I should wrap "setupDatabase" in another promise?

    The user would call db.init().then(function() {}) and operate on the db once the init promise is completed.

    The code above works so far, "mixinObjectStores" is simply exporting the stores to the namespace synchronously.

    Any thoughts?

    Friday, February 17, 2012 6:39 PM

Answers

  • It doesn't seem like mixinObjectStores does anything async... if it really is just a "mix-in" then it's just extending some JS object and thus should process almost instantaneously, right?

    I don't really condone the practice of passing the handler function pointers deeper and deeper into oblivion. Each function that instantiates a promise object should (by good practice) have complete, error, and progress called within it's own scope. So I would do it like this (obviously I can't test this code to make sure it doesn't suck):

    function initAsync() {
        return new WinJS.Promise(function (complete, error, progress) {
            var opening;
            opening = window.indexedDB.open("kids", 1);
            opening.onupgradeneeded = function (event) {
                setupDatabaseAsync(tx).then(function (db) {
                    complete(db);
                });
            };
            opening.onsuccess = function (event) {
                var db = event.target.result;
                complete(mixinObjectStores(db));
            };
            opening.onerror = error;
        });
    };
    
    function setupDatabaseAsync(tx) {
        return new WinJS.Promise(function (complete, error, progress) {
            var kids;
            tx.oncomplete = function (event) {
                complete(mixinObjectStores(db));
            };
            tx.onerror = error;
            kids = tx.db.createObjectStore('kids', {
                keyPath: 'id',
                autoIncrement: true
            });
            kids.createIndex('byName', 'name');
        });
    };
    
    function mixinObjectStores(database) {
        return myExtendThingy(database, objectStoreMixin);
    };

    Also I want to point out that progress should not report "success." The complete function reports success. You should have progress report interim progress.


    Senior Dev for Windows Phone Services


    Wednesday, February 22, 2012 12:57 AM

All replies

  • Hi Phil,

    The guidance is if you think something will take longer than 50ms, it should be async.

    -Jeff


    Jeff Sanders (MSFT)

    Monday, February 20, 2012 9:26 PM
    Moderator
  • and to make mixinObjectStores async in JS I would have to use setTimeout?
    Tuesday, February 21, 2012 5:30 AM
  • It doesn't seem like mixinObjectStores does anything async... if it really is just a "mix-in" then it's just extending some JS object and thus should process almost instantaneously, right?

    I don't really condone the practice of passing the handler function pointers deeper and deeper into oblivion. Each function that instantiates a promise object should (by good practice) have complete, error, and progress called within it's own scope. So I would do it like this (obviously I can't test this code to make sure it doesn't suck):

    function initAsync() {
        return new WinJS.Promise(function (complete, error, progress) {
            var opening;
            opening = window.indexedDB.open("kids", 1);
            opening.onupgradeneeded = function (event) {
                setupDatabaseAsync(tx).then(function (db) {
                    complete(db);
                });
            };
            opening.onsuccess = function (event) {
                var db = event.target.result;
                complete(mixinObjectStores(db));
            };
            opening.onerror = error;
        });
    };
    
    function setupDatabaseAsync(tx) {
        return new WinJS.Promise(function (complete, error, progress) {
            var kids;
            tx.oncomplete = function (event) {
                complete(mixinObjectStores(db));
            };
            tx.onerror = error;
            kids = tx.db.createObjectStore('kids', {
                keyPath: 'id',
                autoIncrement: true
            });
            kids.createIndex('byName', 'name');
        });
    };
    
    function mixinObjectStores(database) {
        return myExtendThingy(database, objectStoreMixin);
    };

    Also I want to point out that progress should not report "success." The complete function reports success. You should have progress report interim progress.


    Senior Dev for Windows Phone Services


    Wednesday, February 22, 2012 12:57 AM
  • Thanks Bryan for your answer! I still need to get my head wrapped around promisses and I will try to follow the rule not to pass the promise handlers out of function scope from now on. It also makes the code much more readable!

    Since I have a nice Spec'ed Metro App for BDD I will just throw in your code and see if I get a green run. If I do, your answer will become green here too :)

    Thanks a lot MSFT for your outstanding support here!

    Wednesday, February 22, 2012 6:46 AM
  • I also want to note, you don't need to call mixinObjectStores in your complete callback of the transaction. Once the upgradeneeded event is completed, the onsuccess callback on the open call of the indexeddb will get called with the correct version of the database.

    In your case you would work on the old version and would recieve onversionchange events on the IDatabase object.

    If you want some more information about indexededdb, I blogged about several subjects.

    www.kristofdegrave.be

    Wednesday, March 21, 2012 7:00 AM