Передавання callback в іншу функцію
Щоб передати callback, вкажіть функцію як звичайний аргумент під час виклику іншої функції, а всередині приймальної функції викличте її за іменем параметра. Це можливо тому, що в JavaScript функції є значеннями (first-class citizens): їх можна присвоювати змінним, класти в масиви і передавати як аргументи.
Теорія
TL;DR
- Callback передається як звичайний аргумент:
doSomething(afterDone). - Передавайте посилання на функцію, без дужок. Дужки означають виклик і передадуть результат, часто
undefined. - Усередині приймальної функції колбек викликають за іменем параметра:
callback(). - Можна передати іменовану функцію, анонімну функцію або стрілкову функцію прямо на місці виклику.
- Приймальній функції байдуже, що саме робить callback: вона отримує поведінку ззовні.
Швидкий приклад
function doSomething(callback) {
console.log('Doing something...');
callback(); // call the callback we were given
}
function afterDone() {
console.log('Done!');
}
doSomething(afterDone);Вивід:
Doing something...
Done!Три способи передати callback
Форма запису різна, суть однакова: у параметр callback потрапляє функція.
// 1. Іменована функція, передаємо посилання на неї
function afterDone() {
console.log('Done!');
}
doSomething(afterDone);
// 2. Анонімна функція прямо в аргументі
doSomething(function () {
console.log('Done!');
});
// 3. Стрілкова функція, найкоротший запис
doSomething(() => {
console.log('Done!');
});| Спосіб | Коли зручний |
|---|---|
| Іменована функція | Логіку перевикористовують у кількох місцях, її легко протестувати окремо |
Анонімна function | Потрібен власний this або arguments усередині колбека |
| Стрілкова функція | Короткий одноразовий обробник, this береться із зовнішньої області |
Передавання аргументів у callback
Приймальна функція сама вирішує, з якими аргументами викликати колбек. Викликач лише описує, що робити з цими значеннями.
function doSomething(callback) {
const result = 42;
callback(result); // pass data into the callback
}
doSomething(value => {
console.log('Got', value); // Got 42
});Якщо треба «зафіксувати» власні аргументи заздалегідь, загорніть виклик у стрілкову функцію або застосуйте bind.
function greet(name) {
console.log('Hello, ' + name);
}
doSomething(() => greet('Maria')); // wrapper keeps the argument
doSomething(greet.bind(null, 'Oleh')); // the same via bindВиклик замість передавання: головна пастка
afterDone це функція, afterDone() це вже її результат. Дужки в аргументі виконують функцію негайно, і приймальна функція отримає не поведінку, а значення, яке та повернула.
doSomething(afterDone); // correct: pass the function itself
doSomething(afterDone()); // wrong: runs now and passes undefinedТой самий принцип працює для будь-якого API, що приймає колбек: setTimeout(fn, 100), addEventListener('click', fn), array.map(fn).
Захист від відсутнього колбека
Якщо параметр необов'язковий, перевірте його перед викликом або дайте значення за замовчуванням, інакше отримаєте TypeError: callback is not a function.
function doSomething(callback = () => {}) {
console.log('Doing something...');
callback();
}
doSomething(); // works even without an argumentТипові помилки
- Передавати
afterDone()замістьafterDone: функція виконається одразу, а в параметр потрапитьundefined. - Ставити дужки в
setTimeout(sayHi(), 100)і дивуватися, що таймер нічого не робить. - Викликати колбек, не перевіривши, що його справді передали, і отримувати
TypeError. - Передавати метод об'єкта напряму,
obj.handler, і втрачатиthis. Рятує стрілкова обгортка абоbind. - Очікувати, що значення з асинхронного колбека буде доступне одразу після виклику функції: воно з'явиться лише тоді, коли колбек справді виконається.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.