在WinJS中链接IndexedDB

时间:2013-07-22 14:25:10

标签: winjs promise

我正在用HTML / JS编写Windows 8应用程序,并在带有单击事件处理程序的表单上有一个按钮。单击按钮时,第一件事是:

WinJS.Promise.then(openDB()).done(console.log("PROMISE DONE"));

openDB函数如下所示:

function openDB() {
    console.log("openDb...");
    var req = indexedDB.open("MyDB", 1);
    req.onsuccess = function(evt) {
        var data = evt.target.result;
        console.log("openDb DONE");
    }
}

(我还在req对象上进行了onerror和onupgradeneeded回调,但为了简洁而将这些回调留下了。)

我明显误解了承诺应该如何运作但我认为我可以在承诺上链接多个THEN调用,并且最终调用DONE只会在所有THEN调用执行时触发。问题是控制台显示' openDb ...',然后是' PROMISE DONE'后面跟着' OpenDb完成'。因此,在THEN呼叫之前正在执行DONE呼叫。任何人都可以解释为什么会这样吗?

1 个答案:

答案 0 :(得分:1)

这里的根本问题是“then”方法返回一个新的承诺。如果您调用的函数返回一个promise,那就是返回的promise(并因此被链接)。如果您的函数未返回承诺,则返回一个新的(已完成的)承诺,该承诺将为您提供返回的值。

查看你的openDB函数,它会返回什么?实际上,它返回undefined。更重要的是,它启动了异步工作,然后立即返回;异步操作直到稍后才完成。因此,你得到了你所看到的行为。

所以你需要做的是让openDB返回一个在数据库打开操作完成之前无法完成的promise。 WinJS承诺真的很糟糕,因此API很难看。希望他们能填写Win8.1中缺少的部分。

因此,您需要创建一个新的承诺,并在异步工作完成后完成它。看起来像这样:

function openDB() {
    var complete;
    var = new Promise(function (c, e, p) {
        complete = c;
    });

    console.log("openDb...");
    var req = indexedDB.open("MyDB", 1);
    req.onsuccess = function(evt) {
        var data = evt.target.result;
        console.log("openDb DONE");
        complete(data);
    }

    return p;
}

new Promise(function (c, e, p) { ... })调用会创建一个新的promise对象。您传递的函数本身传递了三个函数 - 一个用于成功完成对象(c表示完成),一个用于调用,如果promise未成功完成(e表示错误),另一个用于调用报告进度(p表示进度) )。我们将完成回调函数转换为变量,以供日后使用。

现在,在indexedDB的成功回调中,请注意我们调用完整的回调,传递我们获得的数据。这将使承诺成为完成状态。

最后,我们返回创建的承诺。请注意,此返回同步发生;函数在调用onsuccess处理程序之前返回。

这应该可以让你得到你想要的东西 - 在数据库打开完成之前它会阻止承诺链。您可能应该将错误处理程序连接到某些东西。

现在,完成此操作后,对WinJS.Promise.then()的调用也是错误的,或者至少是不必要的。你应该这样做:

openDB().done(function () { console.log('Promise Done'); });

由于openDB本身返回一个promise,你不需要在你正在做的另一个promise中额外包装。