Обратный вызов - это функция, которая передается в другую функцию в качестве аргумента, который может быть вызван позже внутри функции.

Синхронные обратные вызовы

Синхронный означает, что операторы кода выполняются последовательно друг за другом.

function print(number, result) {
    console.log(`${number} is ${result}`);
}
function checkEvenOrOdd(number, callback) {
  const result =  (number % 2 === 0) ? 'Even' : 'Odd';
  callback(number, result);
}
checkEvenOrOdd(56, print);
// 56 is Even

Здесь обратный вызов выполняется немедленно и не ожидает завершения какой-либо асинхронной операции. Вот почему это синхронный обратный вызов.

Асинхронные обратные вызовы

Если обратный вызов выполняется после завершения асинхронной операции, то это асинхронный обратный вызов.

Давайте посмотрим на один пример, где мы возьмем заказ и распечатаем его.

function takeOrder() {
    setTimeout(() => {
       return (Math.random() * 10) <= 5 ? 'Coffee' : 'Tea';
    }, 1000);
}
let order = takeOrder();
console.log('Order is for: ' + order);
// Order is for: undefined

Здесь, в функции takeOrder, setTimeout запустится через 1 секунду, и к этому времени оператор console.log уже будет выполнен, поэтому напечатанное значение порядка как неопределенное.

Теперь мы можем решить эту проблему, если сможем записать наше сообщение в консоль только после того, как данные будут возвращены из takeOrder. Это можно сделать, передав функцию обратного вызова takeOrder, которая будет вызываться внутри функции takeOrder.

function takeOrder(callback) {
    setTimeout(() => {
        const order = (Math.random() * 10) <= 5 ? 'Coffee' : 'Tea';
        callback(order);
    }, 1000);
}
takeOrder((order) => {
    console.log('Order is for: ' + order);
});
// Order is for: Tea

Здесь через 1 секунду будет вызвана функция обратного вызова, и оператор консоли будет выполнен с правильным значением порядка.

Примечание. Вывод функции takeOrder может отличаться в вашем случае, поскольку мы используем Math.random() для определения стоимости заказа.

Обработка ошибок с помощью обратных вызовов

Мы можем передавать разные обратные вызовы как для успешных, так и для неудачных сценариев.

function takeOrder(success, failure) {
    setTimeout(() => {
        const random = (Math.random() * 10);
        if(random < 8) {
            const order = random < 4 ? 'Coffee' : 'Tea';
            success(order);
        } else {
            failure('Order Not Available');
        }
        
    }, 1000);
}
takeOrder(
    (order) => {
        console.log('Order is for: ' + order);
    },
    (error) => {
        console.log(error);
    }
);

Вложенные обратные вызовы

Давайте посмотрим на процесс заказа один за другим.

function takeOrder(callback) {
    setTimeout(() => {
        const order = (Math.random() * 10) <= 5 ? 'Coffee' : 'Tea';
        callback(order);
    }, 1000);
}
function makeOrder(order, callback) {
    setTimeout(() => {
        callback(order + ' is prepared');
    }, 1000);
}
function serveOrder(order, callback) {
    setTimeout(() => {
        callback(order + ' is served');
    }, 1000);
}
takeOrder((order) => {
    console.log('Order is for: ' + order);
    makeOrder(order, (orderStatus) => {
        console.log(orderStatus);
        serveOrder(order, (orderStatus) => {
            console.log(orderStatus);
        })
    })
});

Выход

Order is for: Coffee
Coffee is prepared
Coffee is served

Здесь makeOrder вызывается, когда приходит ответ от takeOrder. Аналогично serveOrder вызывается, когда приходит ответ от makeOrder. Здесь мы вкладываем обратные вызовы друг в друга для последовательного выполнения функций.

Если вложенность обратных вызовов увеличивается, это называется адом обратных вызовов, где трудно управлять обратными вызовами, и это снижает удобочитаемость кода. Взгляните на пример ада обратного вызова.

takeOrder((order) => {
    makeOrder(order, () => {
        serveOrder(order, () => {
            provideBill(order, () => {
                takeBill(order, () => {
                    // some more callbacks
                })
            })
        })
    })
});

Этот ад обратного вызова можно исправить с помощью обещания и async / await.

В JavaScript есть несколько встроенных методов, которые принимают обратный вызов в качестве аргумента.

// Array.map()
array.map((element) => {
    // your code here
});
// setTimeout
setTimeout(() => {
    // your code here
}, timeout);

Давайте посмотрим на некоторые другие методы, которые принимают обратный вызов.

Array.filter(), Array.reduce(), Array.find(), Array.sort(), Array.forEach(), setInterval(), addEventListener(), Promise.then(), Promise.catch() и т. Д.

Вам также может понравиться

Спасибо за уделенное время ☺️
Для других блогов о веб-разработке посетите jscurious.com