2012-10-16 15 views
8

Credo di avere una domanda relativamente semplice, ma continuo a ragionare e persino Google non mi sta dando una risposta con cui posso lavorare.query WebSQL Javascript all'interno di ciclo. Come sapere quando finito?

Fondamentalmente sto provando a copiare alcuni record che sono memorizzati localmente usando WebSQL. La copia non è un problema, ma ho bisogno di sapere quando tutte le azioni di copia sono terminate prima che il mio programma possa procedere.

Le chiamate WebSQL sono rese asincrone, quindi l'unico modo per me di solito fare queste cose è utilizzando la funzione di callback. Tuttavia, poiché le query vengono eseguite all'interno di un ciclo for, non è possibile utilizzare la funzione di callback poiché verrà attivata alla prima query completata, come mostrato nel codice.

Il codice è il seguente:

function copyRecords(old_parent_id, new_parent_id, callback){ 
    var db = openDatabase('test', '1.0', 'test', 50 * 1024 * 1024); 
    db.transaction(function (tx) { 
     tx.executeSql('SELECT * FROM table WHERE parent_id = ?', [old_parent_id], function(tx, results){ 
      for(var i = 0; i < results.rows.length; i++){ 
       db.transaction(function (tx2) { 
        tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)', [results.rows.item(i).name, new_parent_id], callback); 
       }) 
      } 
     }); 
    }); 
} 

ho provato anche chiamando la funzione di callback quando i == results.rows.length, ma questo non mi asure che tutte le query sono stati completati.

Immagino che alcuni di voi abbiano già riscontrato lo stesso problema, quindi qualsiasi aiuto su come risolvere questo problema e assicurarsi che la funzione di callback venga chiamata solo quando il ciclo for è completo è molto apprezzato.

Grazie in anticipo.

+0

E 'fattibile per spostare transacion interna fuori dal ciclo attraverso i risultati, in modo che il ciclo di inserti va dentro la transazione completamente? – Stan

risposta

8

L'approccio più comune per questo sarebbe quella di utilizzare un callback asincrona ricorsivo per elaborare ogni singolo record invece di un ciclo for.

Mentre sono rimasti altri record, la richiamata asincrona si chiama. Quando non ci sono più record, può chiamare il callback fornito.

Il codice qui sotto dovrebbe sostituire il contenuto del vostro gestore di callback interna:

(function nextRecord() { 
    var row = results.rows.shift(); 
    if (row) { 
     db.transaction(function (tx2) { 
      tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)', 
       [row.item(i).name, new_parent_id], nextRecord); 
     }); 
    } else { 
     callback(); 
    } 
})(); 
+0

Grazie per la risposta! Non ho mai pensato di usare le funzioni ricorsive! – user1749815

+0

grazie per l'idea, ma sembra che i risultati di web-sql non supportano la funzione shift(), in quanto non è un array. Quindi ho dovuto incrementare manualmente un contatore, e ha funzionato! – Matthieu

2

Questa operazione è consigliata mantenendo il conteggio del numero di esecuzioni della funzione "richiamata" e procedendo solo quando raggiunge l'intero importo del set di risultati.

Ecco il codice con le modifiche:

function copyRecords(old_parent_id, new_parent_id, callback){ 
    var db = openDatabase('test', '1.0', 'test', 50 * 1024 * 1024); 
    db.transaction(function (tx) { 
     tx.executeSql('SELECT * FROM table WHERE parent_id = ?', [old_parent_id], function(tx, results){ 
      if (results.rows.length == 0) 
       callback(); // don't forget this case! 
      else { 
       var nbrInserted = 0; // This will keep track of how many have been inserted 
       for(var i = 0; i < results.rows.length; i++){ 
        db.transaction(function (tx2) { 
         tx2.executeSql('INSERT INTO table (name, parent_id) VALUES (?, ?)', [results.rows.item(i).name, new_parent_id], function() { 
          ++nbrInserted; // increment this for every insert 
          if (nbrInserted == results.rows.length) // check if complete 
           callback(); // Do your callback. 
         }); 
        }); 
       } 
      } 
     }); 
    }); 
} 

Quanto a me, ho trovato le API asincroni di WebSQL ad essere un po 'combersome, e dal momento che i database WebSQL rischiano di andare via (lo standard è stato lasciato cadere), consiglierei a tutti di passare a SequelSphere. È un database relazionale HTML5/JavaScript che funziona su tutti i browser e tutte le piattaforme. Memorizza anche i dati in localStorage, offrendo tutti i vantaggi di WebSQL, senza tutti i problemi.

Fammi sapere se la soluzione di cui sopra non funziona per te.

Buona fortuna!

John ...

+0

Dovresti davvero aver dichiarato il tuo interesse in SequelSphere. – Alnitak

+0

Buon punto. Hai assolutamente ragione. Per favore perdonami ... Sono collegato a SequelSphere e non ho potuto fare a meno di dare la spina. –

+0

p.s. i callback asincroni non sono ingombranti - vedi la mia risposta su come fare questo _right! _ – Alnitak

Problemi correlati