JavaScript: Callbacks vs Promise vs Async/Await

Programación asíncrona con JavaScript y uso de callbacks, promesas y async/await.

Rodríguez Patiño, Eduardo
2020-12-01 | 2,033 lecturas

Antes de comenzar con esta publicación vamos asumir que entiendes el concepto de la programación asíncrona, pero si tienes dudas te compartimos el siguiente enlace para que le des una repasada.

¿QUÉ VAMOS APRENDER?

Vamos a crear una función que se ejecutará asíncronamente haciendo uso de la función setTimeout y vamos a ver como capturar su valor de respuesta o "return" implementando ya sea un callback, promise o async/await.

El siguiente código es síncrono:

function doSomething() {
    return 'Hola KODOTI';
}

Y podemos obtener su respuesta de la siguiente manera:

console.log(doSomething()); // Hola KODOTI

Pero sí este código fuera asíncrono, no vamos a poder obtener su respuesta porque el hilo de ejecución actual de ese código ha cambiado. Seguramente, intentaríamos hacer algo como esto:

function doSomething() {
    return setTimeout(() => {
        return 'hola KODOTI';
    }, 0);
}

console.log(doSomething()); // No retorna el mensaje

La solución a este problema es a través de los callbacks.

CALLBACKS

Un callback es una función que será pasada como parámetro y ejecutada en el mismo hilo del setTimeout.

function doSomething(fn) {
    setTimeout(() => {
        fn('hola KODOTI');
    }, 0);
}

doSomething(m => {
    console.log(m);
})

LO MALO DEL CALLBACK

Su problema esta en que el código se vuelve algo tedioso de implementar, dificultando la lectura y el mantenimiento. Por ejemplo, veamos este escenario:

function doSomething(fn) {
    setTimeout(() => {
        fn('hola KODOTI');
    }, 0);
}

function doSomething2(fn) {
    setTimeout(() => {
        fn('Aprende más, haciendo pequeños proyectos ..');
    }, 0);
}

function doSomething3(fn) {
    setTimeout(() => {
        fn('Hecho por Developers para Developers');
    }, 0);
}

Ahora tenemos 3 funciones a ejecutar y su implementación sería un callback trás otro callback.

doSomething(m1 => {
    console.log(m1);

    doSomething2(m2 => {
        console.log(m2);

        doSomething3(m3 => {
            console.log(m3);
        });
    });
});

Nuestro código puede producir el famoso callback hell donde Ryu de Street Fighter te lo explica.


PROMISES

Con la llegada de ES6 se estandarizó las promesas el cual nos ofrece una mejor API para trabajar el tema de la asincronidad haciendo que nuestro código sea más legible de implementar. Veamos un ejemplo de como quedaría nuestra función doSomething.

function doSomething() {
    return new Promise(resolve =>
        setTimeout(() => resolve('hola KODOTI'))
    );
}

La instancia de la promesa recibe el parámetro resolve que será el encargado de resolver lo que nuestro setTimeout o código asíncrono busca realizar.

La promesa devuelta nos da el acceso a un nuevo método llamado then donde es podremos interceptar lo que se especifico en el resolve.

doSomething()
   .then(x => console.log(x));
// hola KODOTI

ASYNC/AWAIT

Si bien las promesas nos dan una mejor lectura de código, la llegada de async/await con ES7 lo facilita mucho más.

Lo que haremos es decirle a nuestra función doSomething que entre en armonía para ejecutar código asíncrono.

async function doSomething() {
    return new Promise(resolve =>
        setTimeout(() => resolve('hola KODOTI'))
    );
}

Luego de agregar async a nuestro función nos olvidamos del Then y podemos hacer que la lectura sea aún mucho más sencillo asignando el retorno de la función una variable a través del await.

let msg = await doSomething();
console.log(msg); // hola KODOTI

¿TIENES DUDAS?

Deja un comentario y te daré una mano.