2010-10-11 16 views
13

Je travaille sur un peu de JavaScript qui interagit avec une base de données SQLite côté client, via les nouvelles API window.openDatabase(...), database.transaction(...) et les API associées. Comme la plupart d'entre vous le savent lorsque vous exécutez une requête de cette manière, il s'agit d'un appel asynchrone, ce qui est généralement bien. Vous pouvez effectuer l'appel et gérer les résultats selon les besoins avec les rappels.Requête synchrone pour la base de données Web SQL

Dans ma situation actuelle, je travaille sur un algo pour un client qui fait de la hiérarchie dans la base de données stockée localement. La partie de l'algo avec laquelle je rencontre des problèmes nécessite de commencer à une ligne, qui a une référence à un "parent" (par id) qui est une autre ligne plus haut dans la table. Je dois continuer à marcher jusqu'à cet arbre jusqu'à ce que j'atteigne la racine. Le problème est que je suis à un point où je ne suis pas sûr de savoir comment utiliser une requête de style asynchrone avec un rappel pour continuer à alimenter les ID de parent de boucle. Idéalement, je pourrais bloquer la requête pour que je puisse tout faire dans la boucle. Voici les principales parties de mon installation actuelle:

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

Comme vous pouvez l'imaginer, cela ne fonctionne pas bien. hierarchyArr obtient un "undefined" poussé dedans, puis le script plante quand il essaye de vérifier le type de rs [0]. Lorsque j'essaie de le configurer avec un rappel (db.getRSAndCallback(sql, callbackFunc), que j'ai utilisé pour les requêtes précédentes, non interdépendantes), c'est pire: la boucle interne décolle comme un fou parce que l'identifiant n'est pas mis à jour; probablement parce que la boucle maintient l'interpréteur JavaScript tellement occupé qu'il ne remplit jamais réellement rs. Dans certains tests artificiels où j'ai forcé la boucle interne à se rompre après quelques itérations, tous les rappels ont commencé à arriver à la fin, une fois la boucle terminée. Le "standard" (tel qu'il est actuellement) à http://dev.w3.org/html5/webdatabase/#synchronous-database-api semble indiquer qu'il existe une API synchrone, mais je n'ai vu aucun signe de cela sur les navigateurs basés sur WebKit.

Quelqu'un peut-il offrir des suggestions sur comment je pourrais, a. formuler correctement ces requêtes itératives et interdépendantes en utilisant des rappels ou, b. d'une manière ou d'une autre, l'appel se produit réellement de manière synchrone ou apparemment synchrone.

Un grand merci d'avance à tous ceux qui prennent une pause à ce petit problème apparemment délicat.

Naim

P.S. Voici la mise en œuvre du client de db.getRS pour référence:

. 
. 
. 
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, je voulais aussi mentionner: Si je débogage le script et je mis un point d'arrêt sur 'droite hierarchyArr.push (rs [0]); 'le script fonctionne très bien. En passant par là le jeu d'enregistrements est rempli et id est mis à jour et il marche la hiérarchie. Désactivez le point d'arrêt et laissez-le s'exécuter et il se bloque lorsque j'ai mentionné ci-dessus, sans doute parce que la pause dans l'exécution en cours permet de terminer la requête. – Naim

Répondre

9

I utilisé callbacks et une fermeture pour résoudre un problème similaire, pensez à:

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

Dans la suite de cet exemple, le dossier a une propriété parent pour définir sa relation avec d'autres dossiers. Comme un document.Ce qui suit vous obtiendrez le chemin d'un document à l'aide d'une fermeture (succès):

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

Cela a fini par être exactement comment j'ai fini par l'implémenter. Merci d'avoir pris le temps de mettre votre code ici pour les autres! J'avais oublié de faire ça. :) – Naim

+0

Je suis désolé, pourriez-vous s'il vous plaît expliquer s'il y a une différence avec la solution ci-dessus entre avoir la variable de données [] dans la portée externe par opposition à être dans la fonction de rappel? – Stuart

1

Vous pouvez utiliser les callbacks avec une fermeture à votre pile de requêtes restantes. Ou vous pourriez utiliser la récursivité, en passant la pile en tant que paramètres.

+0

Oui, ce sont deux bonnes options. Je pense que la récursivité sera probablement le moyen d'aller dans cette situation, mais voulait tenir le coup pour d'autres idées. Heureusement, mon traitement de l'ensemble de données complet n'est pas interdépendant entre les enregistrements, donc ce ne sera pas trop compliqué. – Naim