Suponga que mantiene una biblioteca que expone una función getData
. Sus usuarios lo llaman para obtener datos reales:
var output = getData();
los datos internos se guardan en un archivo para que los implemente getData
utilizando Node.js integrado fs.readFileSync
. Es obvio tanto getData
y fs.readFileSync
son funciones de sincronización. Un día le dijeron que cambiara la fuente de datos subyacente a un repositorio como MongoDB, al que solo se puede acceder de forma asincrónica. También se le dijo que evitara enojar a sus usuarios, la getData
API no se puede cambiar para devolver simplemente una promesa o exigir un parámetro de devolución de llamada. ¿Cómo cumple ambos requisitos?
La función asincrónica que usa callback / promise es el ADN de JavasSript y Node.js. Cualquier aplicación JS no trivial probablemente esté impregnada de este estilo de codificación. Pero esta práctica puede conducir fácilmente a la llamada pirámide de la fatalidad. Peor aún, si algún código en cualquier llamador en la cadena de llamadas depende del resultado de la función asíncrona, ese código también debe estar incluido en la función de devolución de llamada, imponiendo una restricción de estilo de codificación al llamador. De vez en cuando, encuentro la necesidad de encapsular una función asíncrona (a menudo proporcionada en una biblioteca de terceros) en una función de sincronización para evitar una refactorización global masiva. La búsqueda de una solución sobre este tema generalmente terminaba con Node Fiberso paquetes npm derivados de él. Pero las fibras simplemente no pueden resolver el problema al que me enfrento. Incluso el ejemplo proporcionado por el autor de Fibers ilustra la deficiencia:
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
Salida real:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Si la función Fiber realmente convierte la función asíncrona en reposo en sincronizada, la salida debería ser:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
Creé otro ejemplo simple en JSFiddle y busqué código para producir el resultado esperado. Aceptaré una solución que solo funcione en Node.js, por lo que puede solicitar cualquier paquete npm a pesar de no funcionar en JSFiddle.
Respuestas:
deasync convierte la función asíncrona en sincronización, implementada con un mecanismo de bloqueo al llamar al bucle de eventos Node.js en la capa de JavaScript. Como resultado, deasync solo bloquea el código subsiguiente para que no se ejecute sin bloquear todo el hilo, ni provocar una espera ocupada. Con este módulo, aquí está la respuesta al desafío jsFiddle:
(descargo de responsabilidad: soy coautor de
deasync
. El módulo se creó después de publicar esta pregunta y no se encontró una propuesta viable).fuente
function AnticipatedSyncFunction(){ var ret; setTimeout(function(){ var startdate = new Date() //console.log(startdate) ret = "hello" + startdate; },3000); while(ret === undefined) { require('deasync').runLoopOnce(); } return ret; } var output = AnticipatedSyncFunction(); var startdate = new Date() console.log(startdate) console.log("output="+output);
y espero ver 3 segundos de diferencia en la salida de fecha!También hay un módulo de sincronización npm. que se utiliza para sincronizar el proceso de ejecución de la consulta.
Cuando desee ejecutar consultas paralelas de forma síncrona, entonces el nodo restringe para hacerlo porque nunca espera una respuesta. y el módulo de sincronización es perfecto para ese tipo de solución.
Código de muestra
enlace de referencia: https://www.npmjs.com/package/sync
fuente
Si. Dentro de la fibra, la función espera antes de iniciar sesión
ok
. Las fibras no hacen que las funciones asíncronas sean síncronas, pero permiten escribir código de apariencia síncrona que usa funciones asíncronas y luego se ejecutará de forma asíncrona dentro de un archivoFiber
.No puedes. Es imposible sincronizar el código asincrónico. Deberá anticipar eso en su código global y escribirlo en estilo asíncrono desde el principio. Ya sea que envuelva el código global en una fibra, use promesas, generadores de promesas o devoluciones de llamada simples, depende de sus preferencias.
Tanto las promesas como las fibras pueden hacer eso.
fuente
fs
métodos síncronos .Tienes que usar promesas:
Me gustan más las definiciones de funciones de flecha. Pero cualquier cadena de la forma "() => {...}" también podría escribirse como "función () {...}"
Entonces, topDog no es asíncrono a pesar de llamar a una función asíncrona.
EDITAR: Me doy cuenta de que muchas de las veces que necesita para envolver una función asíncrona dentro de una función de sincronización está dentro de un controlador. Para esas situaciones, aquí hay un truco de fiesta:
Utilizando esto con devoluciones de llamada, puede hacer un ajuste que no use promesas:
Al aplicar este truco a un EventEmitter, puede obtener los mismos resultados. Defina el oyente de EventEmitter donde definí la devolución de llamada y emita el evento donde llamé a la devolución de llamada.
fuente
No puedo encontrar un escenario que no se pueda resolver usando fibras de nodo. El ejemplo que proporcionó utilizando fibras de nodo se comporta como se esperaba. La clave es ejecutar todo el código relevante dentro de una fibra, para que no tenga que iniciar una nueva fibra en posiciones aleatorias.
Veamos un ejemplo: digamos que usa algún marco, que es el punto de entrada de su aplicación (no puede modificar este marco). Este marco carga módulos de nodejs como complementos y llama a algunos métodos en los complementos. Digamos que este marco solo acepta funciones sincrónicas y no utiliza fibras por sí mismo.
Hay una biblioteca que desea usar en uno de sus complementos, pero esta biblioteca es asincrónica y tampoco desea modificarla.
El hilo principal no se puede ceder cuando no se está ejecutando fibra, ¡pero aún puede crear complementos utilizando fibras! Simplemente cree una entrada de envoltura que inicie todo el marco dentro de una fibra, para que pueda generar la ejecución de los complementos.
Desventaja: si el marco usa
setTimeout
oPromise
s internamente, escapará del contexto de la fibra. Esto se puede evitar al burlarsesetTimeout
,Promise.then
y todos los controladores de eventos.Así es como se puede producir una fibra hasta que
Promise
se resuelva a. Este código toma una función asincrónica (devolución de promesa) y reanuda la fibra cuando se resuelve la promesa:framework-entry.js
async-lib.js
my-plugin.js
my-entry.js
Cuando se ejecuta
node framework-entry.js
se generará un error:Error: yield() called with no fiber running
. Si lo ejecutanode my-entry.js
, funciona como se esperaba.fuente
Hacer que el código de Node.js se sincronice es esencial en algunos aspectos, como la base de datos. Pero la ventaja real de Node.js radica en el código asincrónico. Como es de un solo hilo sin bloqueo.
podemos sincronizarlo usando una funcionalidad importante Fiber () Use await () y defer () llamamos a todos los métodos usando await (). luego reemplace las funciones de devolución de llamada con defer ().
Código asincrónico normal: utiliza funciones de CallBack.
Sincronice el código anterior usando Fiber (), await () y defer ()
Espero que esto sea de ayuda. Gracias
fuente
Hoy en día este patrón generador puede ser una solución en muchas situaciones.
Aquí un ejemplo de indicaciones de consola secuenciales en nodejs usando la función async readline.question:
fuente
No debería estar mirando lo que sucede alrededor de la llamada que crea la fibra, sino más bien lo que sucede dentro de la fibra. Una vez que esté dentro de la fibra, puede programar en estilo sincronizado. Por ejemplo:
Dentro de la fibra que llamas
f1
,f2
ysleep
como si estuvieran sincronizados.En una aplicación web típica, creará la fibra en su despachador de solicitudes HTTP. Una vez que haya hecho eso, puede escribir toda la lógica de manejo de solicitudes en estilo de sincronización, incluso si llama a funciones asíncronas (fs, bases de datos, etc.).
fuente
while(true) handleNextRequest()
bucle. Envolver cada gestor de solicitudes en una fibra lo haría.Al principio luché con esto con node.js y async.js es la mejor biblioteca que he encontrado para ayudarlo a lidiar con esto. Si desea escribir código síncrono con el nodo, el enfoque es de esta manera.
este programa SIEMPRE producirá lo siguiente ...
fuente
async
funciona en su ejemplo porque esmain
, que no se preocupa por la persona que llama. Imagine que todo su código está envuelto en una función que se supone que devuelve el resultado de una de sus llamadas a funciones asíncronas. Se puede comprobar fácilmente que no funciona agregandoconsole.log('return');
al final de su código. En tal caso, la salida dereturn
ocurrirá despuésin main
pero antesstep 1
.Javascript es un lenguaje de un solo hilo, ¡no quieres bloquear todo tu servidor! El código asincrónico elimina las condiciones de carrera al hacer explícitas las dependencias.
¡Aprenda a amar el código asincrónico!
Eche un vistazo al
promises
código asincrónico sin crear una pirámide de infierno de devolución de llamada. Recomiendo la biblioteca promiseQ para node.jshttp://howtonode.org/promises
EDITAR: esta es, con mucho, mi respuesta más controvertida, el nodo ahora tiene la palabra clave yield, que le permite tratar el código asíncrono como si fuera síncrono. http://blog.alexmaccaw.com/how-yield-will-transform-node
fuente