programacion - llamar funcion javascript desde jquery
Cómo llamar a una función de JavaScript asíncrono y bloquear al llamante original (5)
Tengo una situación interesante en la que mi mente generalmente inteligente no ha podido encontrar una solución para :) Aquí está la situación ...
Tengo una clase que tiene un método get () ... este método se llama para obtener preferencias de usuario almacenadas ... lo que hace es llamar a algún proveedor subyacente para obtener los datos ... tal como está escrito ahora, está llamando un proveedor que habla cookies ... entonces, get () llama a providerGet (), digamos, providerGet () devuelve un valor y get () lo pasa a la persona que llama. La persona que llama espera una respuesta antes de que continúe su trabajo, obviamente.
Aquí está la parte difícil ... Ahora estoy tratando de implementar un proveedor de naturaleza asíncrona (usando el almacenamiento local en este caso) ... así, el proveedorGet () regresará de inmediato, habiendo enviado una llamada al almacenamiento local que , algún tiempo después, llame a una función de devolución de llamada que se le pasó ... pero, dado que providerGet () ya se devolvió, y así se hizo () ahora por extensión al original llamado, obviamente no ha devuelto los datos recuperados reales .
Entonces, la pregunta es simplemente ¿hay una manera de "bloquear" esencialmente la devolución de providerGet () hasta que vuelva la llamada asíncrona? Tenga en cuenta que para mis propósitos no me preocupan las implicaciones de rendimiento que esto pueda tener, solo estoy tratando de averiguar cómo hacer que funcione.
No creo que haya una manera, ciertamente sé que no he podido encontrarla ... así que quise tirarla y ver qué pueden hacer otras personas :)
edición: estoy aprendiendo ahora que el núcleo del problema, el hecho de que la API de sql web es asíncrona, puede tener una solución ... resulta que también hay una versión síncrona de la API, algo que no me di cuenta ... Estoy leyendo los documentos ahora para ver cómo usarlo, pero eso resolvería el problema muy bien ya que la única razón por la que el proveedorGet () se escribió de forma sicrónica fue para permitir que ese proveedor ... el código que se obtiene ( ) es parte de mi propia capa de abstracción por encima de varios proveedores de almacenamiento (cookies, web sql, localStorage, etc.) por lo que el mínimo común denominador tiene que ganar, lo que significa que si uno es asíncrono, TODOS tienen que ser asíncronos ... el único una que era web sql ... así que si hay una manera de hacerlo de forma síncrona, mi punto se vuelve discutible (aunque creo que es una pregunta interesante, aunque genéricamente)
edit2: Ah, bueno, parece que no hay ayuda ... parece que la versión síncrona de la API no se implementa en ningún navegador e incluso si se especificó que solo se puede usar desde subprocesos de trabajo, por lo que no Parece que ayudaría de todos modos. Aunque, al leer algunas otras cosas, parece que hay una manera de resolver este truco usando la recursión ... Ahora estoy combinando un código de prueba, lo publicaré cuando esté funcionando, parece una muy interesante Manera de sortear cualquier situación de forma genérica.
edit3: Según mis comentarios a continuación, realmente no hay manera de hacer exactamente lo que quería. La solución a la que voy para resolver mi problema inmediato es simplemente no permitir el uso de web SQL para el almacenamiento de datos. No es la solución ideal, pero como esa especificación está cambiando y no se implementa ampliamente de todos modos, no es el fin del mundo ... con suerte, cuando esté adecuadamente soportada, la versión síncrona estará disponible y puedo conectar un nuevo proveedor para ella. ser bueno para ir Sin embargo, genéricamente, no parece haber ninguna forma de sacar este milagro ... confirma lo que esperaba que fuera el caso, pero desearía estar equivocado esta vez :)
¿Por qué no hacer que la persona que llama original pase una devolución de llamada propia para get()
? Esta devolución de llamada contendría el código que se basa en la respuesta.
El método get()
reenviará la devolución de llamada a providerGet()
, que luego la invocará cuando invoque su propia devolución de llamada.
El resultado de la recuperación se pasaría a la devolución de llamada del llamante original.
function get( arg1, arg2, fn ) {
// whatever code
// call providerGet, passing along the callback
providerGet( fn );
}
function providerGet( fn ) {
// do async activity
// in the callback to the async, invoke the callback and pass it the data
// ...
fn( received_data );
// ...
}
get( ''some_arg'', ''another_arg'', function( data ) {
alert( data );
});
Cuando se inicia el método asíncrono, abriría algún tipo de diálogo modal (que el usuario no puede cerrar) y les dice que la solicitud está en proceso. Cuando la solicitud finalice, cierre el modal en su devolución de llamada.
Una forma posible de hacer esto es con jqModal , pero eso requiere que cargues jQuery en tu proyecto . No estoy seguro si esa es una opción para ti o no.
Esto es feo, pero de todos modos creo que la pregunta es algo que implica que se desea una solución fea ...
- En su función de obtención, serialice su consulta en una cadena.
- Abra un iframe, pasando (A) esta consulta serializada y (B) un número aleatorio en la cadena de consulta a este iframe
- Su iframe tiene algún código javascript que lee la consulta SQL y el número de su propia cadena de consulta
- Su iframe comienza a ejecutar la consulta de forma asíncrona .
- Cuando su consulta de iframe finaliza de forma asíncrona, la envía, junto con el número aleatorio a su servidor, diga a /write.php?rand=###&reslt="blahblahblah "
- Write.php guarda esta información en algún lugar
- De vuelta en su script principal, después de crear y cargar el iframe, crea una solicitud AJAX síncrona a su servidor, diga a /read.php?rand=####
- /read.php bloquea hasta que la información escrita esté disponible, luego la devuelve a su página principal
Como alternativa, para evitar enviar los datos a través de la red, en lugar de eso, podría hacer que su iframe codifique el resultado en una imagen generada por el lienzo que el navegador almacena en caché (de manera similar al método utilizado por la cookie Zombie). Luego, su secuencia de comandos de bloqueo intentará cargar continuamente esta imagen una y otra vez (con un pequeño retardo generado por la red en cada solicitud) hasta que la versión en caché esté disponible, lo que podría reconocer a través de algún indicador que haya configurado para indicar que se realizó. .
No, no puedes bloquear hasta que finalice la llamada asíncrona. Es así de simple.
Parece que ya lo sabes, pero si quieres usar llamadas ajax asíncronas, debes reestructurar la forma en que se usa tu código. No puede simplemente tener un método .get () que realice una llamada ajax asíncrona, bloquee hasta que esté completo y devuelva el resultado. El patrón de diseño más utilizado en estos casos (por ejemplo, ver todas las API de javascript de Google que hacen redes) es hacer que la persona que llama le pase una función de finalización. La llamada a .get()
iniciará la operación asíncrona y luego regresará de inmediato. Cuando la operación se complete, se llamará a la función de finalización. La persona que llama debe estructurar su código en consecuencia.
Simplemente no puede escribir código de javascript de procedimiento secuencial y directo cuando utiliza redes asíncronas como:
var result = abc.get()
document.write(result);
El patrón de diseño más común es así:
abc.get(function(result) {
document.write(result);
});
Si su problema tiene varias capas de llamada de profundidad, las devoluciones de llamada pueden pasar a diferentes niveles e invocarse cuando sea necesario.
genera un hilo de trabajador web para que realice la operación asíncrona por ti. Pase la información que necesita para realizar la tarea más un ID único. el truco es que envíe el resultado a un servidor web cuando finalice.
Mientras tanto ... la función que generó el trabajador web envía una solicitud ajax al mismo servidor web, usa el indicador síncrono del objeto xmlhttprequest (sí, tiene una opción síncrona). ya que se bloqueará hasta que se complete la solicitud http, solo puede hacer que su secuencia de comandos del servidor web examine la base de datos en busca de actualizaciones o lo que sea hasta que se le envíe el resultado.
feo, lo se pero se bloquearía sin acaparar cpu: D
básicamente
function get(...) {
spawnWebworker(...);
var xhr = sendSynchronousXHR(...);
return xhr.responseTEXT;
}