2008-10-18 13 views
17

Estoy trabajando con una API de JavaScript donde la mayoría de las funciones son asincrónicas. La API es WebKit JavaScript Database API que es un enlace a un subconjunto de funciones para manipular bases de datos SQLite3. Entiendo la decisión de diseño para sincronizar las cosas y no bloquear y proporcionar una interfaz de usuario receptiva. En mi situación, sé que mi uso de las llamadas API asíncronas se ejecutará rápidamente. Dado que este es el caso, me gustaría proporcionar a mis desarrolladores una API de contenedor más limpia y fácil de usar que obliga a las llamadas sincrónicas.Patrón para ajustar una función de JavaScript asíncrona para que sea sincrónico

Aquí está la llamada asincrónica

db.executeSql(sqlStatement, function(result) { 
    // do something with result 
}); 

Y esto es lo que me gustaría ser capaz de hacer

var result = dbWrapper.executeSql(sqlStatement); 
// do something with result 

¿Hay un patrón de diseño/manera de hacer esto? Se prefiere un ejemplo de código escrito o vinculado al código. La plataforma de destino/broswer es Mobile Safari en el iPhone.

Gracias

+0

Será interesante ver si usted consigue una respuesta, porque sospecho que simplemente no es posible (por lo menos sin soporte de hilos, que Safari no va a darte). –

Respuesta

1

si está utilizando jQuery Ajax: $ .ajax()

puede establecer el atributo de asynch en false, y entonces tendrá una solicitud de sincronización Ajax al servidor .

+2

Miré la forma en que jQuery implementa su función $ .ajax() con el uso de un booleano asíncrono, pero resulta que simplemente pasa el parámetro asíncrono a la función XMLHttpRequest.open que se implementa en código "nativo" (no js) y por lo tanto puede forzar el comportamiento sincrónico. – pfeilbr

1

Estamos utilizando GWT RPC que también tiene una API asíncrona. La solución que estamos utilizando actualmente para hacer varias llamadas asíncronas en serie es llamada encadenamiento:

callA(function(resultA) { 
    callB(resultA, function(resultB) { 
     callC(); //etc. 
    }); 
}); 

Este enfoque anidado logra lo que quiere pero es prolijo y difícil de leer para los recién llegados. Uno de los enfoques que hemos investigado es la adición de las llamadas que tenemos que hacer a una pila y ejecutarlas en orden:

callStack = [ 
    callA(), 
    callB(), 
    callC() 
]; 

callStack.execute(); 

A continuación, la pila de llamadas podría administrar:

  1. La invocación de las llamadas en serie (es decir, el cableado en el primer ejemplo)
  2. Pasar el resultado de un desvío a otro.

Sin embargo, dado que Java no tiene referencias de función, cada llamada en la pila de llamadas requeriría una clase anónima, por lo que nos quedamos cortos de dicha solución. Sin embargo, puede tener más éxito en javascript.

¡Buena suerte!

10

Lo sentimos, JavaScript no proporciona las primitivas del lenguaje (por ejemplo, hilos o coroutines) para que las cosas asincrónicas actúen de forma síncrona o viceversa.

En general, * solo obtiene un hilo de ejecución, por lo que no puede obtener una devolución de llamada desde un temporizador o XMLHttpRequest Readystatechange hasta que la pila de llamadas que conducen a la creación de la solicitud se haya desencriptado por completo.

Así que, en resumen, no puedes hacerlo; el enfoque con cierres anidados en la página WebKit que ha vinculado es la única forma que conozco de hacer que el código sea legible en esta situación.

*: excepto en algunas situaciones oscuras que no le ayudaría y generalmente se consideran errores

+1

Eso tiene perfecto sentido. Gracias por la explicación clara. – pfeilbr

+1

Actualización 2014, JavaScript ahora contiene primitivos del lenguaje (corutinas) para tratar con esto, aunque el soporte se limita actualmente a NodeJS, Chrome bajo una bandera y Firefox. https://github.com/petkaantonov/bluebird/blob/master/API.md#promisecoroutinegeneratorfunction-generatorfunction---function –

4

Usted puede intentar algo como:

function synch() 
{ 
    var done = false; 
    var returnVal = undefined; 

    // asynch takes a callback method 
    // that is called when done 
    asynch(function(data) { 
     returnVal = data; 
     done = true; 
    }); 

    while (done == false) {}; 
    return returnVal; 
} 

pero que puede congelar su navegador durante el transcurso de la método de asincronización ...

O vea Narrativa JavaScript: Narrativa JavaScript es una pequeña extensión del lenguaje JavaScript que habilita las capacidades de bloqueo para devoluciones de eventos de eventos asíncronos. Esto hace que el código asincrónico sea refrescantemente legible y comprensible.

http://neilmix.com/narrativejs/doc/index.html

Mike

+3

JavaScript no tiene hilos, esto nunca funcionará. Una vez que se inicia el ciclo 'while ', nunca terminará. – naomik

+0

tienes razón, leerme después de un par de años me hace sentir un poco tonto;) –

+0

No te culpes por ello. De hecho, pensé que esto también funcionaría antes de intentarlo por mí mismo ^.^ – naomik

0

Esta realidad no implementar el funcionamiento síncrono de la consulta db, pero esto fue mi solución para un fácil manejo. Básicamente use la función de llamada como la función de devolución de llamada y pruebe el argumento de resultados. Si la función recibe resultados, los analiza, si no, se envía a sí mismo como una devolución de llamada al método de consulta.

render: function(queryResults){ 
    if (typeof queryResults != 'undefined'){ 
    console.log('Query completed!'); 
    //do what you will with the results (check for query errors here) 

    } else { 
    console.log('Beginning query...'); 
    this.db.read(this.render); //db.read is my wrapper method for the sql db, and I'm sending this render method as the callback. 
    } 
} 
+0

Es posible que también tenga una función de devolución de llamada por separado. Hacer que la función de llamada también sea la función de devolución de llamada simplemente confunde la situación – Dean

8

StratifiedJS le permite hacer exactamente eso.

Incluso hay un artículo sobre cómo aplicarlo en el almacenamiento del navegador: http://onilabs.com/blog/stratifying-asynchronous-storage

y esta es la biblioteca estratificado JavaScript que utiliza https://gist.github.com/613526

El ejemplo es como sigue:

var db = require("webdatabase").openDatabase("CandyDB", ...); 
try { 
    var kids = db.executeSql("SELECT * FROM kids").rows; 
    db.executeSql("INSERT INTO kids (name) VALUES (:name);", [kids[0]]); 
    alert("done"); 
} catch(e) { 
    alert("something went wrong"); 
} 

tal vez un poco tarde, pero la tecnología no existía en ese entonces;)

+0

Enlace a GitHub Fuente: https://github.com/onilabs/stratifiedjs –

0

No estoy seguro si este es el lugar correcto, pero estoy aquí buscando respuestas para hacer llamadas sincrónicas en Firefox. la solución sería eliminar la devolución de llamada onreadystatechange y hacer una llamada directa. Esto es lo que había encontrado y mi solución synchronous call back with rest service

Cuestiones relacionadas