2011-12-19 10 views
9

Al desarrollar una aplicación PhoneGap móvil tuve un problema interesante. Necesitaba consultar sobre 10 elementos de datos de la base de datos (a través de la API de SQLite de PhoneGaps) ... Al igual que muchas API de JavaScript, esta era asincrónica. Cuando hiciste tu consulta, pasarías un controlador de "éxito".Obteniendo comportamiento sincrónico en javascript?

Ahora, mi preferencia en este caso hubiera sido un método de consulta síncrona que solo se devolvió cuando se completó. Entonces podría haber escrito un código de línea recta que consultara cada uno de los 10 elementos 1 tras otro.

Debido a la naturaleza asíncrona de PhoneGap (en realidad, veo esto todo JS sin embargo) me vi obligado a escribir una bestia que tenía este aspecto:

db.query("SELECT...", success() { 
    db.query("SELECT...", success() { 
     db.query("SELECT...", success() { 
      db.query("SELECT...", success() { 
       db.query("SELECT...", success() { 
       } 
      } 
     } 
    } 
} 

Y esto es sólo la mitad de lo más profundo que tenía que ir (y muy simplificada ...) ... Cuando, si hubiera estado usando SQLite en C, que podría haber hecho algo así, simplemente:

db.query("SELECT...", resultA); 
db.query("SELECT...", resultB); 
db.query("SELECT...", resultC); 
db.query("SELECT...", resultD); 
db.query("SELECT...", resultE); 

me parece que el enfoque manejador de éxito es grande cuando solo tienes que ir 1 o 2 niveles de profundidad ... Pero, se derrumba completamente cuando necesitas más tha n que ...

¿Es su biblioteca, o característica de una biblioteca en algún lugar que hace esto más fácil?

Respuesta

7

Este es un problema tan frecuente en la comunidad que muchos patrones and libraries han surgido para combatirlo.

Mi favorito es promesas. Realicé una presentación sobre las promesas como una solución al problema asincrónico en algunos eventos; Puedes ver mis diapositivas en SlideShare: Callbacks, Promises, and Coroutines (oh my!): The Evolution of Asynchronicity in JavaScript. También explica por qué la asincronía es necesaria, en resumen, porque JavaScript tiene un único hilo.

Para el ejemplo particular que das, echa un vistazo a la diapositiva 53 y más cerca. En resumen, en el supuesto db.query volvió una promesa, que se vería así:

db.query("SELECT...") 
    .then(function (a) { 
    return db.query("SELECT..." + a); 
    }) 
    .then(function (b) { 
    return db.query("SELECT..." + b); 
    }) 
    .then(function (c) { 
    return db.query("SELECT..." + c); 
    }) 
    .then(function (d) { 
    return db.query("SELECT..." + d); 
    }) 
    .then(function (e) { 
    return db.query("SELECT..." + e); 
    }); 

Por supuesto, se hace mucho más agradable si no es necesario utilizar los resultados de una consulta para la siguiente:

Q.all([ 
    db.query("SELECT..."), 
    db.query("SELECT..."), 
    db.query("SELECT..."), 
    db.query("SELECT..."), 
    db.query("SELECT...") 
]).spread(function (a, b, c, d, e) { 
    // ... 
}); 
+0

Biblioteca guay. Es bueno saber que mi respuesta no es una locura, ya que eso es lo que hace la última muestra de código que tienes. +1 – cdeszaq

3

Una simplificación básica sería poner las consultas en una lista y tener el mismo controlador de éxito simplemente llame a la siguiente consulta en la lista. Tendría que mantener un puntero a la consulta que se está ejecutando actualmente, pero sería más limpio (al menos desde la apariencia del código) le dará un comportamiento sincrónico.

Esto funcionaría para cualquier cierre porque puede simplemente establecer los valores de la lista en un grupo de fragmentos de código, y luego ejecutar todo en orden.

3

Si es sólo la anidación de que te molesta, simplemente encadenar los métodos por nombre:

function success1() { 
    // do stuff to handle success 
    db.query("SELECT...", success2); 
} 

function success2() { 
    db.query("SELECT...", success3); 
} 

function success3() { 
    db.query("SELECT...", success4); 
} 

function success4() { 
    // do something 
} 

db.query("SELECT...", success1); 

esto no funcionará si alguno de esos manipuladores de éxito interno necesita acceso a algo que se definió en su alcance léxico, pero ese puede no ser el caso (e incluso si lo es, aún podría pasar esos valores como argumentos a la siguiente función en la cadena).

1

Existe un Framework de código abierto conocido como Siminov Hybrid, proporciona ORM para Native (Java) y Web (JavaScript).Al usar esto, puede hacer que todas las operaciones de la base de datos sean síncronas, porque este marco usa el canal de comunicación proporcionado por Android que es Sincrónico.

Es muy fácil integrar PhoneGap con este marco. Con esto, puede trabajar con ORM nativo y Web ORM al mismo tiempo.

http://siminov.github.io/android-hybrid

Cuestiones relacionadas