Οι συναρτήσεις callback είναι συναρτήσεις που περνιούνται ως ορίσματα σε άλλες συναρτήσεις. Η συνάρτηση callback μπορεί στη συνέχεια να κληθεί για να πυροδοτήσει μια επόμενη ενέργεια. Συχνά, τα callbacks χρησιμοποιούνται για να χειριστούν τα αποτελέσματα μιας εργασίας που έγινε ή για να χειριστούν μια ενέργεια όταν συμβεί ένα συμβάν. Οι συναρτήσεις callback μπορούν να χρησιμοποιηθούν τόσο στον σύγχρονο όσο και στον ασύγχρονο προγραμματισμό.
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
Μπορείς επίσης να γράψεις callbacks ως έκφραση συνάρτησης:
applySideLength(function squarePerimeter(side) {
return side * 4;
});
Αυτό είναι ένα χρήσιμο μοτίβο στη JavaScript, επειδή η JavaScript είναι σχεδιασμένη ως περιβάλλον εκτέλεσης με ένα μόνο νήμα, όπου μόνο μία κλήση συνάρτησης μπορεί να εκτελεστεί κάθε φορά. Κατά τη διάρκεια της εκτέλεσης, το περιβάλλον εκτέλεσης δεν μπορεί να ανταποκριθεί σε άλλα συμβάντα ούτε να συνεχίσει την εκτέλεση μέχρι να επιστρέψει η συνάρτηση.
Πολλές κλήσεις API (συναρτήσεις εισόδου/εξόδου, χρονόμετρα και ακροατές συμβάντων) χρησιμοποιούν έναν ασύγχρονο μηχανισμό για να βάλουν στην άκρη την τρέχουσα κλήση συνάρτησης μέχρι να ολοκληρωθεί η εργασία. Μόλις αυτή ολοκληρωθεί, μια συνάρτηση callback τοποθετείται στην ουρά μηνυμάτων, ώστε όταν το περιβάλλον εκτέλεσης βρίσκεται ανάμεσα σε κλήσεις συναρτήσεων, τα μηνύματα να υποβάλλονται σε επεξεργασία καλώντας τη συνάρτηση callback.
Είναι επίσης χρήσιμο να χρησιμοποιείς συναρτήσεις callback, επειδή μπορούν να αναφέρονται σε μεταβλητές που βρίσκονται στην εμβέλεια του closure τους, τις οποίες δεν έχει διαθέσιμες η συνάρτηση όπου καλείται αργότερα.
Οι χειριστές συμβάντων είναι μια συνηθισμένη περίπτωση χρήσης των callbacks στη JavaScript. Τα συμβάντα του προγράμματος περιήγησης, όπως τα 'onload' ή 'onclick', είναι σήματα που μπορούν να πυροδοτήσουν την κλήση συναρτήσεων. Η μέθοδος addEventListener ενός αντικειμένου DOM [Document Object Model καταχωρίζει μια συνάρτηση callback που θα κληθεί όταν "ακούσει" ότι συνέβη ένα συμβάν.
document.addEventListener('onload', function () {
alert('The webpage has now been loaded');
});
Στο Node.js, οι συναρτήσεις callback ακολουθούν μια σύμβαση για να ελέγχουν τη ροή ενός προγράμματος. Ακολουθούν αυτό το μοτίβο: το πρώτο όρισμα της συνάρτησης callback μπορεί να λάβει ένα Error ή null. Το δεύτερο και τα επόμενα ορίσματα λαμβάνουν τα δεδομένα που έχει σχεδιαστεί να στέλνει η καλούσα συνάρτηση.
Αν προκύψει κάποιο σφάλμα, το δεύτερο και τα επόμενα ορίσματα μπορεί να μην υπάρχουν, οπότε δεν μπορείς να βασιστείς στο ότι θα υπάρχουν.
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)
Θα δεις συχνά αυτό το μοτίβο όταν έχεις να κάνεις με ασύγχρονες συναρτήσεις, για να σε βοηθήσει με τη ροή ελέγχου.
Οι συνηθισμένες συναρτήσεις του Array χρησιμοποιούν συναρτήσεις callback για να ορίσουν τη συμπεριφορά τους:
Array.prototype.forEach:
Δέχεται ένα callback, το οποίο εφαρμόζει το callback σε κάθε στοιχείο ενός πίνακα.
[1, 2, 3].forEach(function (element) {
doSomething(element);
});
// => doSomething() is invoked 3 times, once with each element
Array.prototype.map
Δέχεται ένα callback, το οποίο εφαρμόζει το callback σε κάθε στοιχείο ενός πίνακα, χρησιμοποιώντας το αποτέλεσμα για να δημιουργήσει έναν νέο πίνακα.
[1, 2, 3].map(function (element) {
return element + 1;
});
// => [2, 3, 4]
Array.prototype.reduce
Δέχεται ένα callback, το οποίο εφαρμόζει το callback σε κάθε στοιχείο ενός πίνακα, περνώντας το αποτέλεσμα στην επόμενη κλήση.
[1, 2, 3].reduce(function (runningSum, element) {
return runningSum + element;
}, 0);
// => 6