Bienvenido, soy Luis y para hoy les traigo un nuevo tutorial.
Índice
Aprenda a promisificar temporizadores de JavaScript
Si alguna vez quisiste then
o await
JavaScript setTimeout
o setInterval
, funciones, no estás solo.
He tenido que usar mucho estos métodos en el trabajo para lidiar con algunos … interesantes … comportamientos de terceros, así que finalmente me familiaricé con las funciones promisorias.
SetTimeout
puede ser simple, y setInterval
es un poco más complicado, así que asegúrese de entender promesas.
const sleep = async (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); } const asyncInterval = async (callback, ms, triesLeft = 5) => { return new Promise((resolve, reject) => { const interval = setInterval(async () => { if (await callback()) { resolve(); clearInterval(interval); } else if (triesLeft <= 1) { reject(); clearInterval(interval); } triesLeft--; }, ms); }); }
Ahí está, si quieres ver por qué, ¡mira a continuación! Pero si eso es todo lo que necesitas, ¡me alegro de poder ayudarte!
Toma este código:
const foo = () => { setTimeout(() => { console.log('Callback based stuff'); console.log('yet another thing'); // lots more stuff }, 2000); }
Lo molesto de setTimeout
es que todo tiene que ir dentro de esa función de devolución de llamada.
Puede resultar engorroso si hay mucho que hacer. Pero no se necesita devolución de llamada adicional cuando usamos await
:
const asyncFoo = async () => { await new Promise((resolve) => setTimeout(resolve, 2000)); console.log('nice'); console.log('way better'); }
¿Que esta pasando aqui? Bueno, como sabes la promesa realmente solo llama una resolución función o función de rechazo después de que algo suceda.
Lo que estamos haciendo es crear un nuevo Promise
y en lugar de pasar una devolución de llamada a setTimeout
, pasamos resolve
.
De esa forma, después de que pasen los milisegundos, es resolve
que se invoca, y nuestra promesa se activa y se resuelve. Entonces podemos await
y hacer lo que queramos. Fácil … pero puede ser incluso más fácil.
La gente tiende a querer usar el setTimeout
funciona como un botón de pausa. Otros idiomas tienen un sleep
función para detener su programa durante un período de tiempo determinado. ¡Hagamos uno!
const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)); } const asyncFoo = async () => { await sleep(2000); console.log('look at this'); await sleep(1000); console.log('getting fancy now'); }
Esta es una función de utilidad simple que realmente puede ser útil, especialmente si se usa más de una vez, ya que anidar setTimeout
se ve realmente terrible.
Si tu quieres setInterval
para funcionar para siempre, estás en un aprieto, pero si solo quieres usarlo para manejar algunos reintentos y luego seguir adelante, puede funcionar.
Para hacerlo, usaremos el mismo truco resolve
como antes, pero también agregaremos una cantidad máxima de intentos. Si no obtenemos algo para entonces, seguiremos adelante y usaremos reject
.
Tenemos que envolver nuestra tarea de intento, una verificación de servidor falsa, en una función y debe devolver verdadero o falso:
// task must return true or false const fakeServerCheck = async () => { console.log('check...'); return Math.random() > 0.8; } const asyncInterval = async (callback, ms, triesLeft = 5) => { return new Promise((resolve, reject) => { const interval = setInterval(async () => { if (await callback()) { resolve(); clearInterval(interval); } else if (triesLeft <= 1) { reject(); clearInterval(interval); } triesLeft--; }, ms); }); } const wrapper = async () => { try { await asyncInterval(fakeServerCheck, 500); } catch (e) { console.log('error handling'); } console.log("Done!"); } wrapper();
La salsa secreta aquí es que nuestra función de tarea devuelve un booleano. De esa manera, podemos saber si seguir adelante o no.
También notarás que estoy agregando un await
antes de callback
aunque fakeServerCheck
es sincrónico.
Eso es porque en la vida real, esa función probablemente estará haciendo algo async
, y estoy tratando de hacer asyncInterval
Funciona lo más cortable
y copiable
posible.
¡Ahí tienes! Con estas dos funciones, sleep
y asyncInterval
no tiene la incómoda combinación de devoluciones de llamada programadas y promesas regulares.
Sé que usar este tipo de temporizadores no es muy común, pero si te encuentras usándolos, esto realmente debería ayudar.
Feliz codificación a todos. Gracias por leer este tutorial.
Añadir comentario