Callbacks en JavaScript

Ana Martínez Aguilar
3 min readMay 28, 2018

Un callback (llamada de vuelta) es una función que recibe como argumento otra función y la ejecuta. En el siguiente ejemplo, la función foo recibe por parámetro otra función, que es el callback. La función foo es la encargada de ejecutar el callback.

function foo(callback) { 
//do something
callback();
}

Es importante tener en cuenta que cuando pasamos un callback solo pasamos la definición de la función y no la ejecutamos en el parámetro. Así, la función contenedora elige cuándo ejecutar el callback.

Un ejemplo muy común de callback es como función escuchadora de un evento.

function showAlert(){
alert('Alerta');
}
button.addEventListener('click', showAlert);

En este ejemplo, showAlert es un callback. También podemos escribir el callback como función anónima:

button.addEventListener('click', function(){
alert('Alerta');
});

Los callbacks también se utilizan para “avisar” cuando una función termina de hacer algo:

function foo(callback) {
console.log("hello")
callback();
}
foo(function(){console.log("finished")});
→ hello
finished

El uso del callback también se conoce como callback pattern, puesto que es esencialmente un patrón al ser una solución para problemas comunes. Además, el uso de callbacks se relaciona con la programación funcional, que especifica el uso de funciones como argumentos. Los callbacks pueden ayudar a no repetir código y a su mantenimiento, a conseguir funciones más específicas y, en ciertos casos, a mejorar el nivel de abstracción y la lectura del código.

Controlar la ejecución asíncrona con callbacks

Los callbacks de por sí son síncronos. En el siguiente ejemplo, es la función contenedora quien elige cuándo se ejecuta el callback, y este se ejecuta sin provocar otro flujo de ejecución.

function foo(val, callback){
if(val == 1){
callback(true);
}
else{
callback(false);
}
}

Por ello, los callbacks son muy útiles para manejar la asincronía en JS. Por ejemplo, nos pueden venir muy bien cuando estamos haciendo testing de elementos asíncronos. Veamos un ejemplo.

Dentro de un test, creamos un setTimeOut (método asíncrono puesto que provoca que haya otro flujo de ejecución). El test puede funcionar incorrectamente porque no se espera a que la operación asíncrona haya terminado y esta no llega a ejecutarse. Para asegurarnos de que el contenido del setTimeOut siempre se ejecute, le pasamos un callback. Hasta que no se haya llamado al callback, JS no saldrá del test (es decir, de la función).

it("checks something of the DOM", function (done) {
foo1();
foo2();
foo3();
function onTimeout() {
expect(parseInt(element.innerHTML)).toEqual(x);
done();
}
setTimeout(onTimeout, 1000);
});

Veamos cuál es el orden de ejecución:

it("restart the counter time", function (done) {
console.log(1);
foo1();
console.log(2);
foo2();
console.log(3);
foo3();
console.log(4);
function onTimeout() {
console.log(5);
expect(parseInt(element.innerHTML)).toEqual(x);
console.log(6);
done();
console.log(7);
}
console.log(8);
setTimeout(onTimeout, 1000);
console.log(9);
});

El orden de ejecución, al pasar el test, es el siguiente:

1
2
3
4
8
9
5
6
7

Con el parámetro done nos aseguramos de que el número 5, 6 y 7 siempre se ejecuten.

Veamos el caso en el que no le pasamos callback al test:

it("restart the counter time", function () {
console.log(1);
foo1();
console.log(2);
foo2();
console.log(3);
foo3();
console.log(4);
function onTimeout() {
console.log(5);
expect(parseInt(element.innerHTML)).toEqual(x);
console.log(6);
}
console.log(8);
setTimeout(onTimeout, 1000);
console.log(9);
});

El orden de ejecución, al pasar el test, es el siguiente:

1
2
4
8
9

Nunca se llega a ejecutar ni el 5 ni el 6.

Callbacks para eliminar el conocimiento en las dependencias

En un código, es usual que existan funciones que dependan de otras funciones. Cuando muchas partes de nuestro código dependen de otras partes, es más fácil que algunos métodos afecten a otros sin que lo hayamos previsto o que cualquier cambio futuro sea complejo y laborioso. En general, cuanto menos dependencia mejor.

Hay varias maneras de eliminar la dependencia y una de ellas es la utilización de callbacks. No se trata de una solución habitual ni tampoco que podamos utilizar en cualquier situación, pero nos puede ayudar en determinados casos.

A través de callbacks, podemos invertir la dependencia a nivel de conocimiento y hacer que una función no tenga conocimiento de la otra función que ejecuta.

Veamos un ejemplo con una cuenta atrás:

var seconds = 20;function startCountDown(){
setInterval(function(){
seconds--;
showSeconds();
}, 1000);
}
function showSeconds(){
console.log(seconds);
}
startCountDown()

La función startCountDown depende de la función showSeconds(). Cada segundo, startCountDown ejecuta la función showSeconds. Si queremos minimizar esta dependencia, podemos hacer que la función startCountdown no tenga conocimiento sobre la función showSeconds pasándole un callback.

var seconds = 20;function startCountDown(onTimeChanged){
setInterval(function(){
seconds--;
onTimeChanged();
}, 1000);
}
function showSeconds(){
console.log(seconds);
}
startCountDown(showSeconds);

--

--