Le funzioni callback sono funzioni passate come argomenti ad altre funzioni. La funzione di callback può quindi essere chiamata per attivare un'azione successiva. Spesso i callback servono a gestire i risultati di un lavoro svolto oppure a gestire un'azione quando si verifica un evento. Le funzioni callback si possono usare nella programmazione sincrona e in quella asincrona.
const sideLength = 5;
// Caller function takes a callback function
function applySideLength(callback) {
return callback(sideLength);
}
// Callback must expect the possible argument from the calling function
function areaOfSquare(side) {
return side * side;
}
applySideLength(areaOfSquare); // => 25
Puoi anche scrivere i callback come espressione di funzione:
applySideLength(function squarePerimeter(side) {
return side * 4;
});
Questo è uno schema utile in JavaScript, perché JavaScript è progettato come un runtime a singolo thread, in cui si può eseguire una sola chiamata di funzione alla volta. Durante l'esecuzione, il runtime non può rispondere ad altri eventi né continuare a eseguire finché la funzione non ha restituito.
Molte chiamate all'API (funzioni di I/O, timer e listener di eventi) usano un meccanismo asincrono per mettere da parte la chiamata di funzione corrente finché il lavoro non è completo. Al termine, una funzione di callback viene inserita nella coda dei messaggi: così, quando il runtime si trova tra una chiamata di funzione e la successiva, i messaggi vengono elaborati chiamando la funzione di callback.
È anche utile usare le funzioni callback, perché possono fare riferimento a variabili nel loro scope di chiusura, che non sono disponibili alla funzione in cui vengono chiamate in seguito.
I gestori di eventi sono un caso d'uso comune dei callback in JavaScript. Gli eventi del browser come 'onload' o 'onclick' sono segnali che possono far chiamare delle funzioni. Il metodo addEventListener di un oggetto del DOM [Document Object Model registra una funzione di callback da chiamare quando «sente» che si è verificato un evento.
document.addEventListener('onload', function () {
alert('The webpage has now been loaded');
});
In Node.js, le funzioni di callback seguono una convenzione per controllare il flusso di un programma. Seguono questo schema: il primo argomento della funzione di callback può ricevere un Error o null; il secondo argomento e quelli successivi ricevono i dati che la funzione chiamante è progettata per inviare.
Se si verifica un errore, il secondo argomento e quelli successivi potrebbero non essere presenti, quindi non puoi contare sulla loro presenza.
function operation(a, b, callback) {
// Work ...
if (/* an error occurs */) {
return callback(new Error('An error occurred'))
}
// On success:
callback(null, data)
}
function callback(error, returnedData) {
if (error) {
// An error occurred, handle it here.
return
}
// No error occurred, continue with the returned data.
}
operation(1, 2, callback)
Vedi spesso questo schema quando lavori con funzioni asincrone, per gestire il flusso di controllo.
Le funzioni comuni di Array usano funzioni di callback per definire il loro comportamento:
Array.prototype.forEach:
Accetta un callback, che applica il callback a ogni elemento di un array.
[1, 2, 3].forEach(function (element) {
doSomething(element);
});
// => doSomething() is invoked 3 times, once with each element
Array.prototype.map
Accetta un callback, che applica il callback a ogni elemento di un array, usando il risultato per creare un nuovo array.
[1, 2, 3].map(function (element) {
return element + 1;
});
// => [2, 3, 4]
Array.prototype.reduce
Accetta un callback, che applica il callback a ogni elemento di un array, passando il risultato alla chiamata successiva.
[1, 2, 3].reduce(function (runningSum, element) {
return runningSum + element;
}, 0);
// => 6