Primero, este es un caso muy específico de hacerlo de manera incorrecta a propósito para adaptar una llamada asincrónica a una base de código muy síncrona que tiene muchos miles de líneas de largo y el tiempo actualmente no permite la capacidad de hacer los cambios para "hacer bien." Me duele cada fibra de mi ser, pero la realidad y los ideales a menudo no encajan. Sé que esto apesta.
Bien, eso fuera del camino, ¿cómo lo hago para poder:
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
Todos los ejemplos (o la falta de ellos) usan bibliotecas y / o compiladores, los cuales no son viables para esta solución. Necesito un ejemplo concreto de cómo hacer que se bloquee (por ejemplo, NO deje la función doSomething hasta que se llame la devolución de llamada) SIN congelar la IU. Si tal cosa es posible en JS.
fuente
Respuestas:
OKAY. pero realmente deberías hacerlo de la manera correcta ... o lo que sea
No, es imposible bloquear el JavaScript en ejecución sin bloquear la interfaz de usuario.
Dada la falta de información, es difícil ofrecer una solución, pero una opción puede ser hacer que la función de llamada realice un sondeo para verificar una variable global y luego establecer la devolución de llamada
data
en global.Todo esto supone que puede modificar
doSomething()
. No sé si eso está en las cartas.Si se puede modificar, entonces no sé por qué no pasarías una devolución de llamada para
doSomething()
que se llame desde la otra devolución de llamada, sino que mejor me detengo antes de meterme en problemas. ;)Oh, qué diablos. Diste un ejemplo que sugiere que se puede hacer correctamente, así que voy a mostrar esa solución ...
Debido a que su ejemplo incluye una devolución de llamada que se pasa a la llamada asíncrona, la forma correcta sería pasar una función para
doSomething()
que se invoque desde la devolución de llamada.Por supuesto, si eso es lo único que está haciendo la devolución de llamada, simplemente pasaría
func
directamente ...fuente
callback
función a lamyAsynchronousCall
función, que hace sus tareas asíncronas e invoca la devolución de llamada cuando se completa. Aquí hay una demostración.Las funciones asíncronas , una característica de ES2017 , hacen que el código asíncrono se vea sincronizado mediante el uso de promesas (una forma particular de código asíncrono) y la
await
palabra clave. Observe también en los ejemplos de código debajo de la palabra claveasync
delante de lafunction
palabra clave que significa una función asíncrona / espera. Laawait
palabra clave no funcionará sin estar en una función preestablecida con laasync
palabra clave. Dado que actualmente no hay ninguna excepción a esto, eso significa que no funcionará ninguna espera de nivel superior (el nivel superior espera, lo que significa una espera fuera de cualquier función). Aunque hay una propuesta para el nivel superiorawait
.ES2017 fue ratificado (es decir, finalizado) como el estándar para JavaScript el 27 de junio de 2017. Async aguardando ya puede funcionar en su navegador, pero si no puede seguir utilizando la funcionalidad utilizando un transpiler javascript como babel o traceur . Chrome 55 tiene soporte completo de funciones asíncronas. Entonces, si tiene un navegador más nuevo, puede probar el código a continuación.
Consulte la tabla de compatibilidad de kangax es2017 para ver la compatibilidad del navegador.
Aquí hay un ejemplo de función de espera asíncrona llamada
doAsync
que toma tres pausas de un segundo e imprime la diferencia horaria después de cada pausa desde la hora de inicio:Cuando la palabra clave de espera se coloca antes de un valor de promesa (en este caso, el valor de promesa es el valor devuelto por la función doSomethingAsync), la palabra clave de espera detendrá la ejecución de la llamada de función, pero no detendrá ninguna otra función y continuará ejecutando otro código hasta que se resuelva la promesa. Después de que la promesa se resuelva, desenvolverá el valor de la promesa y puede pensar en la expresión de esperar y prometer como ahora reemplazada por ese valor desenvuelto.
Entonces, dado que esperar solo pausa, espera y luego desenvuelve un valor antes de ejecutar el resto de la línea, puede usarlo para bucles y llamadas a funciones internas como en el ejemplo a continuación, que recopila las diferencias de tiempo esperadas en un conjunto e imprime el conjunto.
La función asíncrona en sí misma devuelve una promesa, por lo que puede usarla como una promesa con el encadenamiento como lo hago arriba o dentro de otra función de espera asíncrona.
La función anterior esperaría cada respuesta antes de enviar otra solicitud. Si desea enviar las solicitudes simultáneamente, puede usar Promise.all .
Si la promesa posiblemente se rechaza, puede envolverla en un try catch u omitir el try catch y dejar que el error se propague a la llamada catch de las funciones asíncronas / en espera. Debe tener cuidado de no dejar errores de promesa no controlados, especialmente en Node.js. A continuación se muestran algunos ejemplos que muestran cómo funcionan los errores.
Si va aquí , puede ver las propuestas terminadas para las próximas versiones de ECMAScript.
Una alternativa a esto que se puede usar solo con ES2015 (ES6) es usar una función especial que envuelva una función de generador. Las funciones generadoras tienen una palabra clave de rendimiento que puede usarse para replicar la palabra clave de espera con una función circundante. La palabra clave de rendimiento y la función de generador tienen un propósito mucho más general y pueden hacer muchas más cosas que lo que hace la función de espera asíncrona. Si quieres un envoltorio función de generador que se puede utilizar para la réplica asíncrona esperan que volvería a la salida co.js . Por cierto, la función de co, al igual que las funciones de espera asíncrona, devuelve una promesa. Honestamente, en este punto, la compatibilidad del navegador es casi la misma tanto para las funciones de generador como para las funciones asíncronas, por lo que si solo desea la funcionalidad de espera asíncrona, debe usar las funciones asíncronas sin co.js.
El soporte del navegador es bastante bueno ahora para las funciones asíncronas (a partir de 2017) en todos los principales navegadores actuales (Chrome, Safari y Edge) excepto IE.
fuente
Echa un vistazo a JQuery Promises:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
Refactorizar el código:
fuente
dfd.notify(data)
adfd.resolve(data)
Hay una buena solución en http://taskjs.org/
Utiliza generadores que son nuevos en javascript. Por lo tanto, actualmente no está implementado por la mayoría de los navegadores. Lo probé en Firefox, y para mí es una buena manera de ajustar la función asincrónica.
Aquí hay un código de ejemplo del proyecto GitHub
fuente
Usted puede forzar JavaScript asíncrono en NodeJS ser sincronizado con sincronización-RPC .
Sin embargo, definitivamente congelará tu interfaz de usuario, por lo que todavía soy una detractora cuando se trata de si es posible tomar el atajo que debes tomar. No es posible suspender el One And Only Thread en JavaScript, incluso si NodeJS le permite bloquearlo a veces. No se podrán procesar devoluciones de llamada, eventos, nada asíncrono hasta que se resuelva su promesa. Entonces, a menos que usted, el lector, tenga una situación inevitable como el OP (o, en mi caso, esté escribiendo un script de shell glorificado sin devoluciones de llamada, eventos, etc.), ¡NO HAGA ESTO!
Pero así es como puedes hacer esto:
./calling-file.js
./my-asynchronous-call.js
LIMITACIONES
Ambos son una consecuencia de cómo
sync-rpc
se implementa, que es abusando derequire('child_process').spawnSync
:JSON.stringify
, por lo que se perderán funciones y propiedades no enumerables como cadenas de prototipos.fuente
También puede convertirlo en devoluciones de llamada.
fuente
Lo que quieres es realmente posible ahora. Si puede ejecutar el código asincrónico en un trabajador de servicio y el código síncrono en un trabajador web, entonces puede hacer que el trabajador web envíe un XHR sincrónico al trabajador de servicio, y mientras el trabajador de servicio hace las cosas asíncronas, el trabajador web El hilo esperará. Este no es un gran enfoque, pero podría funcionar.
fuente
La idea que espera lograr puede hacerse posible si modifica un poco el requisito
El siguiente código es posible si su tiempo de ejecución es compatible con la especificación ES6.
Más acerca de las funciones asíncronas
fuente
SyntaxError: await is only valid in async functions and async generators
. Sin mencionar que param1 no está definido (y ni siquiera se usa).