承诺不适用于angularjs中的IndexedDB

时间:2015-09-21 12:41:24

标签: javascript angularjs indexeddb angular-promise

我有一个使用IndexedDB的应用程序。最初我大量使用了回调,并决定使用angularjs promises $q来清理它。

FAIL。

http://jsfiddle.net/ed4becky/bumm337e/

angular.module("IDBTest", []);

angular.module("IDBTest")
.service("initSvc", ['$q', function ($q) {
var svc = this;
svc.dbVersion = 1;
svc.open = open;
svc.deleteDB = deleteDB;
var idb = window.indexedDB;

function deleteDB() {
    return $q(function (resolve, reject) {
        idb.webkitGetDatabaseNames().onsuccess = 
            function (sender, args) {
            if (sender.target.result 
                && sender.target.result.length > 0) {
                var db = sender.target.result[0];
                console.log("deleting " + db);
                var request = idb.deleteDatabase(db);
                request.onsuccess = function () {
                    console.log('database ' + db + ' deleted.');
                    resolve();
                };
                request.onerror = function () {
                    reject();
                };
            } else {
                console.log("Nothing to delete");
                resolve();
            };
        };
    });
}

function open(dbName) {
    return $q(function (resolve, reject) {
        var request = idb.open(dbName, svc.dbVersion);
        request.onupgradeneeded = function (e) {
            var db = e.target.result;
            console.log("creating new " + db.name);
            e.target.transaction.onerror = function (e) {
                console.log(e);
            };
            db.createObjectStore("table1", {
                keyPath: "id"
            });
            db.createObjectStore("table2", {
                keyPath: "id"
            });
            db.createObjectStore("table3", {
                keyPath: "id"
            });
        };

        request.onsuccess = function (e) {
            console.log('database ' + dbName + ' open.');
            svc.db = e.target.result;
            resolve();
        };

        request.onerror = function () {
            reject();
        };

    });
}
}]);

angular.module('IDBTest')
.factory('$exceptionHandler', ['$log', function ($log) {
return function (exception, cause) {
    throw exception;
};
 }]);

angular.module('IDBTest')
.run(['initSvc', function (initSvc) {
initSvc.deleteDB()
    .then(initSvc.open('testDatabase'))
    .then(function () {
        console.log(initSvc.db.name + ' initialized');
    });
}]);

这个小提琴显示了我的期望

  1. 删除创建的所有数据库。 然后
  2. 数据库处于打开状态,触发onupgradeneeded 然后
  3. 引用了数据库
  4. 不幸的是,在IDB调用的onsuccess方法中解析了promises之前,then语句似乎被调用了。

    要重新创建,请在控制台打开的情况下运行jsfiddle。可能必须运行它几次才能获得异常,但是大多数时候都会失败,因为在调用数据库打开的onsuccess之前调用last then子句。

    有什么想法吗?

1 个答案:

答案 0 :(得分:2)

我认为问题在于Promise Chain。来自Angular的文档有点令人困惑,但似乎如果回调方法的返回值是一个promise,它将使用一个值来解析;不是承诺。因此,打破了链条。

来自Angular Promise 'Then' Method Documentation

  

then(successCallback, errorCallback, notifyCallback) - 无论如何   当承诺已经或将要解决或拒绝时,请拨打一个   成功或错误回调一旦结果异步   是可用的。使用单个参数调用回调:   结果或拒绝原因。另外,通知回调可能是   在之前调用零次或多次以提供进度指示   承诺得到解决或拒绝。

     

此方法返回通过解析或拒绝的新承诺   successCallback的返回值,errorCallback(除非那个   value是一个promise,在这种情况下,它用值来解析   使用promise chaining)在该承诺中得到解决。它也通知   通过notifyCallback方法的返回值。承诺不能   从notifyCallback方法中解析或拒绝。

我能够用它来初始化它:

angular.module('IDBTest')
    .run(['initSvc', function (initSvc) {
    initSvc.deleteDB()
        .then(function() {
            return initSvc.open('testDatabase');
        })
        .then(function () {
            console.log(initSvc.db.name + ' initialized');
        });
}]);