2010-10-11 27 views
13

Estoy trabajando en un poco de JavaScript que interactúa con una base de datos SQLite del lado del cliente, a través de la nueva window.openDatabase(...), database.transaction(...) y API relacionadas. Como la mayoría de ustedes saben cuando ejecuta una consulta de esta manera, es una llamada asíncrona, que normalmente es buena. Puede hacer la llamada y manejar los resultados según corresponda con devoluciones de llamada.Consulta síncrona a la base de datos web SQL

En mi situación actual, estoy trabajando en un algo para un cliente que realiza una jerarquía caminando en la base de datos almacenada localmente. La parte del algo con el que estoy teniendo problemas requiere comenzar en una fila, que tiene una referencia a un "padre" (por id) que es otra fila más arriba en la tabla. Tengo que seguir caminando por este árbol hasta que llegue a la raíz.

El problema es que estoy en un punto en el que no estoy seguro de cómo usar una consulta de estilo asíncrono con una devolución de llamada para seguir alimentando los identificadores padre de bucle. Idealmente, podría hacer que la consulta se bloquee para que pueda hacerlo todo en el ciclo. Aquí están las partes clave de mi configuración actual:

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

Como se puede imaginar, no funciona bien. hierarchyArr obtiene un "indefinido" insertado en él, y luego el script falla cuando intenta verificar el tipo de rs [0].

Cuando trato de configurarlo con una devolución de llamada (db.getRSAndCallback(sql, callbackFunc), que utilicé para las consultas anteriores, no interdependientes) es peor: el bucle interno despega como loco porque el id no se está actualizando; presumiblemente porque el bucle mantiene el intérprete de JavaScript tan ocupado que nunca llena realmente el rs. En algunas pruebas artificiales en las que obligué al bucle interno a romperse después de algunas iteraciones, todas las devoluciones de llamada comenzaron a llegar al final, una vez finalizado el bucle.

El "estándar" (tal como está ahora) en http://dev.w3.org/html5/webdatabase/#synchronous-database-api parece indicar que hay una API síncrona, pero no he visto ninguna señal de ello en ningún navegador basado en WebKit.

¿Alguien puede ofrecer sugerencias sobre cómo podría, a. formular adecuadamente estas consultas iterativas e interdependientes utilizando devoluciones de llamada o, b. de alguna manera recibe la llamada para que realmente suceda de manera sincrónica o aparentemente sincrónica.

Muchas gracias de antemano para cualquier persona que tome una grieta en este pequeño problema aparentemente complicado.

Naim

P.S. Aquí está la implementación del cliente de db.getRS para referencia:

. 
. 
. 
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, yo también quería mencionar: Si estoy depurar el guión y me puse un punto de interrupción en la derecha ' hierarchyArr.push (rs [0]); 'el script funciona bien. Al recorrerlo, se llena el conjunto de registros y se actualiza la identificación, y recorre la jerarquía. Inhabilite el punto de interrupción y déjelo funcionar y se bloquea donde mencioné anteriormente, sin duda porque la pausa en la ejecución actual le permite finalizar la consulta. – Naim

Respuesta

9

que utilizan devoluciones de llamada y un cierre para resolver un problema similar, tenga en cuenta:

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

En la continuación de este ejemplo, la carpeta tiene una propiedad padres para definir que es relación a otras carpetas. Como lo hace un documento.A continuación se le dará el camino de un documento mediante un cierre (éxito):

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

Eso terminó siendo exactamente cómo terminé implementándolo. ¡Gracias por tomarse el tiempo de poner su código aquí para otros! Me olvidé de hacer eso. :) – Naim

+0

Disculpe, podría explicar si existe alguna diferencia con la solución anterior entre tener la variable data [] en el ámbito externo en lugar de estar en la función de devolución de llamada? – Stuart

1

Usted podría utilizar devoluciones de llamada con un cierre a su pila de consultas restantes. O puede usar la recursión, pasando la pila como parámetros.

+0

Sí, esas son ambas buenas opciones. Creo que la recursión probablemente sea el camino a seguir en esta situación, pero quería esperar otras ideas. Afortunadamente, mi procesamiento del conjunto de datos completo no es interdependiente entre los registros, por lo que no será demasiado desordenado. – Naim

Cuestiones relacionadas