Цепочка IndexedDB в WinJS

Я пишу приложение для Windows 8 в HTML/JS и имею кнопку в форме с обработчиком событий щелчка. При нажатии первое, что делает кнопка, это:

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");
    }
}

(У меня также есть обратные вызовы onerror и onupgradeneeded для объекта req, но для краткости я их не упомянул).

Я явно неправильно понимаю, как должны работать обещания, но я думал, что могу связать несколько вызовов THEN с обещанием, и последний вызов DONE сработает только после выполнения всех вызовов THEN. Проблема в том, что консоль показывает "openDb...", затем "PROMISE DONE", а затем "OpenDb done". Таким образом, вызов DONE выполняется до вызова THEN. Кто-нибудь может объяснить, почему это происходит?


person markp3rry    schedule 22.07.2013    source источник


Ответы (1)


Ваша основная проблема здесь заключается в том, что метод «тогда» возвращает новое обещание. Если функция, которую вы вызвали, возвращает обещание, это обещание, которое возвращается (и, таким образом, цепочка). Если ваша функция не возвращает обещание, возвращается новое (уже завершенное) обещание, которое дает вам возвращаемое значение.

Глядя на вашу функцию openDB, что она возвращает? На самом деле он возвращает undefined. И что еще более важно, он запускает асинхронную работу, а затем немедленно возвращается; асинхронная операция не завершается позже. Таким образом, вы получаете поведение, которое видите.

Итак, что вам нужно сделать, это заставить openDB возвращать промис, который не завершается, пока не завершится операция открытия базы данных. Промисы 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) { ... }) создает новый объект обещания. Передаваемой вами функции передаются три функции: одна для вызова при успешном завершении объекта (c для завершения), одна для вызова в случае неудачного завершения промиса (e для ошибки) и одна для вызова отчета о ходе выполнения (p для выполнения ). Здесь мы помещаем обратный вызов завершения в переменную для последующего использования.

Теперь обратите внимание, что в успешном обратном вызове из indexedDB мы вызываем полный обратный вызов, передавая полученные данные. Это установит обещание в завершенное состояние.

Наконец, мы возвращаем созданный промис. Обратите внимание, что этот возврат происходит синхронно; функция возвращается до того, как будет вызван обработчик onsuccess.

Это должно дать вам то, что вы хотите - он будет удерживать цепочку обещаний до тех пор, пока не завершится открытие базы данных. Вы, вероятно, должны подключить обработчик ошибок к чему-то.

Теперь, после этого вызов WinJS.Promise.then() также неверен или, по крайней мере, не нужен. Вместо этого вы должны просто сделать:

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

Поскольку сам openDB возвращает промис, вам не нужна дополнительная оболочка в другом промисе, который вы делаете.

person Chris Tavares    schedule 22.07.2013
comment
Ух ты! Удивительный ответ. Спасибо. - person markp3rry; 23.07.2013