Una función de devolución de llamada es simplemente una función que se pasa a otra función para que la función pueda llamarla en un momento posterior. Esto se ve comúnmente en las API asincrónicas ; la llamada a la API regresa inmediatamente porque es asincrónica, por lo que le pasa una función que la API puede llamar cuando termine de realizar su tarea asincrónica.
El ejemplo más simple que se me ocurre en JavaScript es la setTimeout()
función. Es una función global que acepta dos argumentos. El primer argumento es la función de devolución de llamada y el segundo argumento es un retraso en milisegundos. La función está diseñada para esperar la cantidad de tiempo adecuada y luego invocar su función de devolución de llamada.
setTimeout(function () {
console.log("10 seconds later...");
}, 10000);
Es posible que haya visto el código anterior antes, pero simplemente no se dio cuenta de que la función que estaba pasando se llamaba función de devolución de llamada. Podríamos reescribir el código anterior para hacerlo más obvio.
var callback = function () {
console.log("10 seconds later...");
};
setTimeout(callback, 10000);
Las devoluciones de llamada se utilizan en todas partes en Node porque Node se construye desde cero para ser asincrónico en todo lo que hace. Incluso cuando habla con el sistema de archivos. Es por eso que muchas de las API internas de Node aceptan funciones de devolución de llamada como argumentos en lugar de devolver datos que puede asignar a una variable. En su lugar, invocará su función de devolución de llamada, pasando los datos que deseaba como argumento. Por ejemplo, puede usar la fs
biblioteca de Node para leer un archivo. El fs
módulo expone dos funciones API únicas: readFile
y readFileSync
.
La readFile
función es asincrónica, mientras readFileSync
que obviamente no lo es. Puede ver que tienen la intención de que use las llamadas asíncronas siempre que sea posible, ya que las llamaron readFile
y en readFileSync
lugar de readFile
y readFileAsync
. A continuación, se muestra un ejemplo del uso de ambas funciones.
Sincrónico:
var data = fs.readFileSync('test.txt');
console.log(data);
El código anterior bloquea la ejecución del hilo hasta que todo el contenido de test.txt
se lee en la memoria y se almacena en la variable data
. En el nodo, esto generalmente se considera una mala práctica. Sin embargo, hay ocasiones en las que es útil, como cuando se escribe un pequeño guión rápido para hacer algo simple pero tedioso y no te importa mucho ahorrar cada nanosegundo de tiempo que puedas.
Asincrónico (con devolución de llamada):
var callback = function (err, data) {
if (err) return console.error(err);
console.log(data);
};
fs.readFile('test.txt', callback);
Primero creamos una función de devolución de llamada que acepta dos argumentos err
y data
. Un problema con las funciones asíncronas es que se vuelve más difícil capturar errores, por lo que muchas API de estilo de devolución de llamada pasan errores como primer argumento de la función de devolución de llamada. Es una buena práctica comprobar si err
tiene un valor antes de hacer cualquier otra cosa. Si es así, detenga la ejecución de la devolución de llamada y registre el error.
Las llamadas síncronas tienen una ventaja cuando se lanzan excepciones porque simplemente puede capturarlas con un try/catch
bloqueo.
try {
var data = fs.readFileSync('test.txt');
console.log(data);
} catch (err) {
console.error(err);
}
En las funciones asincrónicas no funciona de esa forma. La llamada a la API regresa de inmediato, por lo que no hay nada que detectar con try/catch
. Las API asincrónicas adecuadas que utilizan devoluciones de llamada siempre detectarán sus propios errores y luego pasarán esos errores a la devolución de llamada donde puede manejarlo como mejor le parezca.
Sin embargo, además de las devoluciones de llamada, hay otro estilo popular de API que se usa comúnmente llamado promesa. Si desea leer sobre ellos, puede leer la publicación completa del blog que escribí en función de esta respuesta aquí .