Callback (funkcja zwrotna) to funkcja, którą przekazujesz jako argument do innej funkcji, żeby ta wywołała ją w wybranym przez siebie momencie. Zamiast pytać co chwilę „już? już skończyłeś?”, mówisz po prostu: „jak skończysz, to odpal to”. Reszta to detale.
Jak to działa
W językach, w których funkcje są first-class citizens (czyli można je trzymać w zmiennych i podawać dalej — jak w JavaScript, Pythonie czy Go), funkcja to taka sama wartość jak liczba czy string. Możesz ją więc wręczyć innej funkcji, a ta zdecyduje, kiedy ją uruchomić: po kliknięciu, po pobraniu danych z serwera, po przejściu przez każdy element tablicy albo dopiero po odliczeniu timera.
Callbacki świecą najjaśniej przy operacjach asynchronicznych. Gdy odpytujesz API albo czytasz plik, program nie może stać i czekać — robi swoje, a callback odpala się dopiero wtedy, gdy wynik faktycznie przyjdzie. Dzięki temu kod się nie blokuje.
Przykład z praktyki
Klasyk z JavaScriptu — metoda addEventListener przyjmuje callback, który wykona się po kliknięciu:
button.addEventListener('click', () => console.log('kliknięto!'))
Albo przetwarzanie tablicy, gdzie map wywołuje twój callback dla każdego elementu:
[1, 2, 3].map((x) => x * 2)zwróci[2, 4, 6]
W Node.js przez lata królowała konwencja error-first callback: pierwszym argumentem jest błąd (albo null), drugim dane — fs.readFile('plik.txt', (err, data) => { ... }).
Na co uważać
Gdy callbacki zagnieżdżasz jeden w drugim, dostajesz słynne callback hell (zwane też „piramidą zagłady”) — kod ucieka w prawo, a wcięcia robią się coraz głębsze i nieczytelne. Drugi częsty błąd to nie wywołać callbacku w ogóle albo wywołać go dwa razy — wtedy program cicho się zawiesza lub robi coś dwukrotnie. Dlatego w nowoczesnym JS callbacki przy asynchroniczności w dużej mierze ustąpiły miejsca Promise i składni async/await, które czyta się liniowo. Ale callback nie umarł — wciąż jest fundamentem event handlerów, metod tablicowych i wielu API.
Pojęcia powiązane
Higher-order function, Promise, async/await, event loop, event handler, closure (domknięcie), funkcja anonimowa, lambda.