2010-10-11 21 views
13

Pracuję nad fragmentem JavaScript, który współdziała z bazą danych SQLite po stronie klienta, za pośrednictwem nowej wersji window.openDatabase(...), database.transaction(...) i pokrewnych interfejsów API. Jak większość z was wie, kiedy wykonujemy zapytanie w ten sposób, jest to wywołanie asynchroniczne, które zwykle jest dobre. Możesz wykonać połączenie i obsłużyć wyniki odpowiednio w przypadku wywołań zwrotnych.Zapytanie synchroniczne do bazy danych Web SQL

W mojej obecnej sytuacji pracuję nad algo dla klienta, który wykonuje pewną hierarchię w lokalnie przechowywanej bazie danych. Część algo, z którą mam problem, wymaga rozpoczynania od pewnego wiersza, który ma odniesienie do "rodzica" (według id), który jest kolejnym rzędem dalej w tabeli. Muszę podchodzić do tego drzewa, aż dotrę do korzenia.

Problem polega na tym, że jestem w punkcie, w którym nie jestem pewien, jak użyć asynchronicznego zapytania stylu z wywołania zwrotnego, aby nadal podawać identyfikatory macierzyste pętli. Najlepiej byłoby, gdyby zapytanie zostało zablokowane, dzięki czemu mogę zrobić to wszystko w pętli. Oto kluczowe elementy mojej obecnej konfiguracji:

for (i in search.searchResults.resultsArray) 
    { 
     hierarchyArr = new Array(); 
     pageHierarchyArr = new Array(); 
     id = search.searchResults.resultsArray[i].ID; 

     while (id != null && id != "") 
     { 
      var hierarchySql = "SELECT ID, parentID, type, content FROM content WHERE ID = " + id; 

      // This is a prettied up call to database.transaction(...) 
      var rs = db.getRS(hierarchySql); 

      // Ideally the code below doesn't execute until rs is populated 

      hierarchyArr.push(rs[0]); 

      if (rs[0].type == "page") 
      { 
       pageHierarchyArr.push(rs[0]); 

       // Do some additional work 
      } 

      id = rs[0].parentID; 
     } 
    } 

Jak można sobie wyobrazić, nie działa dobrze. hierarchyArr dostaje "undefined" wciśnięty do niego, a następnie skrypt ulega awarii, gdy próbuje sprawdzić typ rs [0].

Kiedy próbuję skonfigurować go za pomocą wywołania zwrotnego (db.getRSAndCallback(sql, callbackFunc), którego użyłem do wcześniejszych, niezwiązanych ze sobą zapytań), jest gorzej: wewnętrzna pętla startuje jak szalona, ​​ponieważ id nie jest aktualizowany; prawdopodobnie dlatego, że pętla sprawia, że ​​interpreter JavaScript jest tak zajęty, że nigdy nie wypełnia on w rzeczywistości rs. W niektórych sztucznych testach, w których zmusiłem wewnętrzną pętlę do zerwania po kilku iteracjach, wszystkie połączenia zwrotne zaczęły przechodzić przez wszystkie na końcu, po zakończeniu pętli.

"Standardowy" (taki jak jest teraz) pod numerem http://dev.w3.org/html5/webdatabase/#synchronous-database-api wydaje się wskazywać, że istnieje synchroniczny interfejs API, ale nie widziałem żadnego znaku tego w przeglądarkach opartych na WebKit.

Czy ktoś może zaproponować, w jaki sposób mogę, a. właściwie sformułować te iteracyjne, współzależne zapytania za pomocą wywołań zwrotnych lub, b. w jakiś sposób uzyskać połączenie, aby rzeczywiście nastąpiło w sposób synchroniczny lub pozornie synchroniczny.

Bardzo dziękuję z góry każdemu, kto ma problem z tym pozornie trudnym problemem.

Naim

P.S. Oto implementacja klienta z db.getRS dla odniesienia:

. 
. 
. 
getRS: function(sql) 
{ 
    var output = []; 
    db.database.transaction(function(tx) 
    { 
     tx.executeSql(sql, [], function(tx,rs) 
     { 
      for(i = 0; i < rs.rows.length; i++) 
      { 
       output.push(rs.rows.item(i)); 
      } 
     }, 
     function(tx, error) { ... } 
    )}); 
    return output; 
}, 
. 
. 
. 
+0

Och, ja też chciałem wspomnieć: Jeśli mam debugowanie skryptu i ustawić breakpoint prawo na ' hierarchyArr.push (rs [0]); 'skrypt działa dobrze. Przechodząc przez to zestaw rekordów jest wypełniany, a identyfikator jest aktualizowany i przechodzi przez hierarchię. Wyłącz punkt przerwania i pozwól mu działać, a on zawiesza się w miejscu, o którym wspomniałem powyżej, bez wątpienia, ponieważ pauza w bieżącej realizacji umożliwia zakończenie zapytania. – Naim

Odpowiedz

9

użyłem wywołania zwrotne i zamknięcie, aby rozwiązać podobny problem, należy rozważyć:

function getFolder(id, callback) { 
var data = []; 
ldb.transaction(function (tx) { 
tx.executeSql('SELECT * FROM folders where id=?', 
    [id], 
    function (tx, results) { 
     if (results.rows && results.rows.length) { 
      for (i = 0; i < results.rows.length; i++) { 
       data.push(results.rows.item(i)); 
      } 
     } 
     if (typeof(callback) == 'function') 
      callback(data); 
    }, 
    function (tx, error) { 
     console.log(error); 
    }); 
}); 
} 

W kontynuacji tego przykładu, folder ma właściwość rodzica zdefiniować to relacja do innych folderów. Podobnie jak dokument.Poniższa będzie Ci ścieżkę dokumentu za zamknięcie (sukces):

function getDocPath(doc, callback) { 
     var path = []; 
     var parent = doc.parent; 
     var success = function(folder) { 
     var folder = folder[0]; 
     parent = folder.parent; 
     path.push({'id':folder.id,'name':folder.name}); 
     if (parent != "undefined") 
      getFolder(parent, success); 
     else 
      if (typeof(callback) == 'function') callback(path.reverse()); 
     } 
     getFolder(parent, success); 
    } 
+1

To w końcu było dokładnie tym, w jaki sposób doszedłem do jego wdrożenia. Dziękujemy za poświęcenie czasu na umieszczenie kodu tutaj dla innych! Zapomniałem to zrobić. :) – Naim

+0

Przykro mi, proszę, czy mógłbyś wyjaśnić, czy jest jakaś różnica w porównaniu z powyższym rozwiązaniem pomiędzy posiadaniem zmiennej data [] w zewnętrznym zakresie, a nie w funkcji wywołania zwrotnego? – Stuart

1

Można użyć wywołania zwrotne z zamknięciem na swój stos pozostałych zapytań. Lub możesz użyć rekursji, przekazując stos jako parametry.

+0

Tak, to są obie dobre opcje. Sądzę, że rekursja będzie prawdopodobnie drogą w tej sytuacji, ale chciała trzymać się innych pomysłów. Na szczęście moje przetwarzanie pełnego zestawu danych nie jest współzależne między rekordami, więc nie będzie zbyt brudne. – Naim

Powiązane problemy