2013-07-22 2 views
0

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

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. Может ли кто-нибудь объяснить, почему это происходит?

ответ

1

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

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

Итак, вам нужно открыть 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 для достижения прогресса). Мы откладываем обратный вызов завершения в переменную здесь для использования позже.

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

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

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

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

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

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

+0

Вау! Удивительный ответ. Благодарю. – markp3rry