在 angularjs 中,Promise 不适用于 IndexedDB

Promises not working for IndexedDB in angularjs

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

来清理它

失败。

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');
    });
}]);

这个fiddle表明我的期望

  1. 所有创建的数据库都被删除。 然后
  2. 一个数据库打开触发了onupgradeneeded 然后
  3. 数据库被引用

不幸的是,then 语句似乎在 IDB 调用的 onsuccess 方法中解决承诺之前被调用。

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

有什么想法吗?

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

来自 Angular Promise 'Then' Method Documentation:

then(successCallback, errorCallback, notifyCallback) – regardless of when the promise was or will be resolved or rejected, then calls one of the success or error callbacks asynchronously as soon as the result is available. The callbacks are called with a single argument: the result or rejection reason. Additionally, the notify callback may be called zero or more times to provide a progress indication, before the promise is resolved or rejected.

This method returns a new promise which is resolved or rejected via the return value of the successCallback, errorCallback (unless that value is a promise, in which case it is resolved with the value which is resolved in that promise using promise chaining). It also notifies via the return value of the notifyCallback method. The promise cannot be resolved or rejected from the notifyCallback method.

我可以用这个初始化它:

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