A continuación, se muestra un ejemplo simple de lo que estoy trabajando actualmente: un flujo de websocket que realiza algunas llamadas asincrónicas como parte de la lógica al consumir los datos entrantes. Estoy imitando llamadas asincrónicas con una función setTimeout de Promise:
function someAsyncWork() { return new Promise(resolve => { setTimeout(() => { resolve('async work done'); }, 5); }); } async function msg() { const msg = await someAsyncWork(); console.log(msg) } const main = async() => { web3.eth.subscribe('pendingTransactions').on("data", async function(tx){ console.log('1st print: ',tx); await msg(); console.log('2nd print: ',tx); }) } main();Ejecutar lo anterior da como resultado una salida de consola como esta:
1st print: 0x8be207fcef... 1st print: 0x753c308980... 1st print: 0x4afa9c548d... async work done 2nd print: 0x8be207fcef... async work done 2nd print: 0x753c308980... async work done 2nd print: 0x4afa9c548d... . . .Entiendo lo que está pasando aquí. Se ejecuta la 'primera impresión', seguida de la espera de las llamadas asincrónicas para cada respuesta de datos. La 'segunda impresión' solo se ejecuta después de que se produzca el 'trabajo asincrónico realizado'. Sin embargo, esto no es exactamente lo que estoy buscando.
Mi lógica tiene condicionales en su lugar, donde cada respuesta de datos primero usará una variable global para verificar una condición, seguida de un trabajo asincrónico si se cumple la condición. El problema es que hay casos en los que algunas respuestas de datos seguirán adelante y ejecutarán un trabajo asíncrono cuando no deberían haberlo hecho: el bucle de eventos de Nodejs no ha tenido la oportunidad de transferir algunas llamadas asíncronas de respuestas de datos anteriores de la cola de devolución de llamadas a la pila de llamadas, ya que la pila estaba demasiado ocupada procesando nuevos datos entrantes. Esto significa que las '2das impresiones' no se han ejecutado (donde se actualiza la variable global) antes de que se hayan procesado los nuevos datos entrantes. Me imagino que someAsyncWork solo se resuelve cuando hay un período libre en el websocket sin datos entrantes.
Mi pregunta es: ¿hay alguna forma de garantizar un procesamiento completo y secuencial de cada dato nuevo? Idealmente, la salida de la consola se vería así:
1st print: 0x8be207fcef... async work done 2nd print: 0x8be207fcef... 1st print: 0x753c308980... async work done 2nd print: 0x753c308980... 1st print: 0x4afa9c548d... async work done 2nd print: 0x4afa9c548d... . . .Puede tener una promesa similar a una cola que siga acumulando promesas para asegurarse de que se ejecuten secuencialmente:
let cur = Promise.resolve(); function enqueue(f) { cur = cur.then(f); } function someAsyncWork() { return new Promise(resolve => { setTimeout(() => { resolve('async work done'); }, 5); }); } async function msg() { const msg = await someAsyncWork(); console.log(msg); } const main = async() => { web3.eth.subscribe('pendingTransactions').on("data", function(tx) { enqueue(async function() { console.log('1st print: ',tx); await msg(); console.log('2nd print: ',tx); }); }) } main();