2010-10-11 4 views
13

Sto lavorando su un po 'di JavaScript che interagisce con un database SQLite lato client, tramite il nuovo window.openDatabase(...), database.transaction(...) e API correlate. Come molti di voi sanno quando si esegue una query in questo modo è una chiamata asincrona, che è in genere buona. È possibile effettuare la chiamata e gestire i risultati in modo appropriato con i callback.Query sincrona al database SQL Web

Nella mia situazione attuale sto lavorando ad un algo per un client che fa una gerarchia che cammina nel database memorizzato localmente. La parte dell'algo con cui ho problemi richiede di iniziare da una riga, che ha un riferimento a un "genitore" (da id) che è un'altra riga più in alto nella tabella. Devo continuare a camminare su quest'albero fino a raggiungere la radice.

Il problema è che sono in un punto in cui non sono sicuro di come utilizzare una query di stile asincrona con un callback per continuare a fornire gli id ​​padre del ciclo. Idealmente potrei ottenere il blocco della query in modo che possa fare tutto nel ciclo. Ecco le parti principali della mia configurazione attuale:

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

Come si può immaginare, non funziona bene. hierarchyArr ottiene un "indefinito" inserito in esso, e quindi lo script si blocca quando tenta di verificare il tipo di rs [0].

Quando provo a configurarlo con un callback (db.getRSAndCallback(sql, callbackFunc), che ho usato per le query precedenti, non interdipendenti, va benissimo) è peggio: il ciclo interno decolla come un matto perché l'ID non viene aggiornato; presumibilmente perché il loop mantiene l'interprete JavaScript così occupato da non riempire mai effettivamente lo rs. In alcuni test artificiali in cui ho forzato il ciclo interno a rompere dopo alcune iterazioni tutte le callback hanno iniziato a passare tutte alla fine, dopo che il ciclo è terminato.

Lo "standard" (come è adesso) a http://dev.w3.org/html5/webdatabase/#synchronous-database-api sembra indicare che c'è un'API sincrona, ma non ho visto alcun segno su alcun browser basato su WebKit.

Qualcuno può offrire suggerimenti su come potrei o, a. formulare correttamente queste query iterative e interdipendenti usando i callback o, b. in qualche modo ottenere la chiamata per effettivamente accadere in modo sincrono o apparentemente sincrono.

Mille grazie in anticipo per chiunque faccia una pausa a questo piccolo problema apparentemente insidioso.

Naim

P.S. Ecco implementazione del cliente di db.getRS per riferimento:

. 
. 
. 
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

Oh, ho anche voluto citare: Se sto debug il copione e ho impostato un diritto punto di interruzione su ' hierarchyArr.push (rs [0]); 'lo script funziona bene. Passando attraverso di esso, il recordset viene popolato e l'id viene aggiornato e percorre la gerarchia. Disabilitare il punto di interruzione e lasciarlo funzionare e si blocca dove ho menzionato sopra, senza dubbio perché la pausa nell'esecuzione corrente consente di terminare la query. – Naim

risposta

9

ho usato callback e una chiusura per risolvere un problema simile, prendere in considerazione:

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

Nella continuazione di questo esempio, la cartella ha una proprietà genitore per definire la sua relazione con altre cartelle. Come fa un documento.Di seguito ti porterà il percorso di un documento utilizzando una chiusura (successo):

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

Finì per essere esattamente come finì per implementarlo. Grazie per aver dedicato del tempo a mettere il tuo codice qui per gli altri! Mi ero dimenticato di farlo. :) – Naim

+0

Mi dispiace, per favore potresti spiegare se c'è qualche differenza con la soluzione sopra riportata tra avere la variabile data [] nello scope esterno invece di essere nella funzione di callback? – Stuart

1

Si potrebbe usare callback con una chiusura al tuo stack di query rimanenti. Oppure potresti usare la ricorsione, passando la pila come parametri.

+0

Sì, quelle sono entrambe buone opzioni. Penso che la ricorsione sarà probabilmente la strada da percorrere in questa situazione, ma volevo resistere per altre idee. Fortunatamente, la mia elaborazione dell'intero set di dati non è interdipendente tra i record, quindi non sarà troppo disordinata. – Naim