Una funzione di callback è semplicemente una funzione che passi a un'altra funzione in modo che la funzione possa chiamarla in un secondo momento. Questo è comunemente visto nelle API asincrone ; la chiamata API ritorna immediatamente perché è asincrona, quindi vi si passa una funzione che l'API può chiamare quando ha terminato di eseguire la sua attività asincrona.
L'esempio più semplice a cui posso pensare in JavaScript è la setTimeout()
funzione. È una funzione globale che accetta due argomenti. Il primo argomento è la funzione di callback e il secondo argomento è un ritardo in millisecondi. La funzione è progettata per attendere la quantità di tempo appropriata, quindi richiamare la funzione di callback.
setTimeout(function () {
console.log("10 seconds later...");
}, 10000);
Potresti aver già visto il codice sopra, ma non ti sei reso conto che la funzione che stavi passando era chiamata funzione di callback. Potremmo riscrivere il codice sopra per renderlo più ovvio.
var callback = function () {
console.log("10 seconds later...");
};
setTimeout(callback, 10000);
I callback vengono utilizzati ovunque in Node perché Node è costruito da zero per essere asincrono in tutto ciò che fa. Anche quando si parla al file system. Ecco perché un sacco di API del nodo interne accettano funzioni di callback come argomenti anziché restituire dati che puoi assegnare a una variabile. Invece richiamerà la tua funzione di callback, passando i dati che volevi come argomento. Ad esempio, potresti usare la fs
libreria di Node per leggere un file. Il fs
modulo espone due funzioni API uniche: readFile
e readFileSync
.
La readFile
funzione è asincrona mentre readFileSync
ovviamente non lo è. Puoi vedere che intendono che tu usi le chiamate asincrone quando possibile poiché le hanno chiamate readFile
e readFileSync
invece di readFile
e readFileAsync
. Ecco un esempio di utilizzo di entrambe le funzioni.
Sincrono:
var data = fs.readFileSync('test.txt');
console.log(data);
Il codice precedente blocca l'esecuzione del thread fino a quando tutto il contenuto di test.txt
viene letto in memoria e archiviato nella variabile data
. Nel nodo questo è generalmente considerato una cattiva pratica. Ci sono volte però in cui è utile, come quando si scrive un breve script veloce per fare qualcosa di semplice ma noioso e non ti interessa molto risparmiare ogni nanosecondo di tempo che puoi.
Asincrono (con callback):
var callback = function (err, data) {
if (err) return console.error(err);
console.log(data);
};
fs.readFile('test.txt', callback);
Per prima cosa creiamo una funzione di callback che accetta due argomenti err
e data
. Un problema con le funzioni asincrone è che diventa più difficile intercettare gli errori, quindi molte API in stile callback passano gli errori come primo argomento alla funzione di callback. È buona norma verificare se err
ha un valore prima di fare qualsiasi altra cosa. In tal caso, interrompere l'esecuzione della richiamata e registrare l'errore.
Le chiamate sincrone hanno un vantaggio quando vengono lanciate eccezioni perché puoi semplicemente catturarle con un try/catch
blocco.
try {
var data = fs.readFileSync('test.txt');
console.log(data);
} catch (err) {
console.error(err);
}
Nelle funzioni asincrone non funziona in questo modo. La chiamata API ritorna immediatamente, quindi non c'è nulla da catturare con il file try/catch
. Le API asincrone corrette che utilizzano i callback rileveranno sempre i propri errori e quindi li trasmetteranno al callback dove potrai gestirlo come meglio credi.
Oltre ai callback, tuttavia, esiste un altro stile popolare di API comunemente utilizzato chiamato promessa. Se desideri leggere su di loro, puoi leggere l'intero post del blog che ho scritto sulla base di questa risposta qui .