Функція зворотного дзвінка - це просто функція, яку ви передаєте в іншу функцію, щоб ця функція могла викликати її пізніше. Це зазвичай спостерігається в асинхронних API ; Виклик API повертається негайно, оскільки він є асинхронним, тому ви передаєте в нього функцію, яку може викликати API, виконуючи свою асинхронну задачу.
Найпростіший приклад, який я можу придумати в JavaScript, - це setTimeout()
функція. Це глобальна функція, яка приймає два аргументи. Перший аргумент - це функція зворотного виклику, а другий - затримка в мілісекундах. Функція призначена для очікування відповідної кількості часу, а потім виклику функції зворотного дзвінка.
setTimeout(function () {
console.log("10 seconds later...");
}, 10000);
Ви, можливо, раніше бачили вищезгаданий код, але просто не усвідомлювали, що функцію, яку ви передавали, називали функцією зворотного виклику. Ми могли б переписати код вище, щоб зробити його більш очевидним.
var callback = function () {
console.log("10 seconds later...");
};
setTimeout(callback, 10000);
Зворотні виклики використовуються повсюдно в Node, тому що Node побудований з нуля, щоб бути асинхронним у всьому, що він робить. Навіть під час розмови з файловою системою. Ось чому багато внутрішніх API вузлів приймають функції зворотного виклику як аргументи, а не повернення даних, які ви можете призначити змінній. Натомість він викликатиме вашу функцію зворотного дзвінка, передаючи дані, які ви хотіли в якості аргументу. Наприклад, ви можете використовувати fs
бібліотеку Node для читання файлу. fs
Модуль надає два унікальних функцій API: readFile
і readFileSync
.
readFile
Функція є асинхронним в той часreadFileSync
, очевидно , немає. Ви можете бачити, що вони мають намір використовувати виклики async, коли це можливо, оскільки вони дзвонили їм, readFile
а readFileSync
не readFile
та readFileAsync
. Ось приклад використання обох функцій.
Синхронні:
var data = fs.readFileSync('test.txt');
console.log(data);
Код вище блокує виконання потоку, поки весь вміст test.txt
буде прочитаний в пам'яті і не збережений у змінній data
. У вузлі це зазвичай вважається поганою практикою. Бувають випадки, коли це корисно, наприклад, коли ви пишете невеликий маленький сценарій, щоб зробити щось просте, але виснажливе, і вам не дуже важливо економити кожен наносекунд часу, який ви можете.
Асинхронний (із зворотним зв'язком):
var callback = function (err, data) {
if (err) return console.error(err);
console.log(data);
};
fs.readFile('test.txt', callback);
Спочатку ми створюємо функцію зворотного виклику, яка приймає два аргументи err
і data
. Одна з проблем асинхронних функцій полягає в тому, що стає складніше відловлювати помилки, тому багато API стилів зворотного виклику передають помилки як перший аргумент функції зворотного виклику. Найкраще практично перевірити, чи err
має значення, перш ніж робити щось інше. Якщо так, зупиніть виконання зворотного дзвінка та введіть помилку.
Синхронні дзвінки мають перевагу, коли є викинуті винятки, оскільки ви можете просто спіймати їх за допомогою try/catch
блоку.
try {
var data = fs.readFileSync('test.txt');
console.log(data);
} catch (err) {
console.error(err);
}
У асинхронних функціях це не працює так. Виклик API повертається негайно, тому з цим нічого спійматиtry/catch
. Правильні асинхронні API, які використовують зворотні дзвінки, завжди вловлюють власні помилки, а потім передають ці помилки у зворотний виклик, де ви можете впоратись із нею, як вважаєте за потрібне.
Крім зворотних зворотних дзвінків, існує ще один популярний стиль API, який зазвичай використовується під назвою обіцянка. Якщо ви хочете прочитати про них, ви можете прочитати всю публікацію в блозі, яку я написав на основі цієї відповіді тут .