What Are Callback Functions In JavaScript?
Tags: javascript, codenewbie, webdev, beginners
Published: 2021-05-18 15:05:21

A callback is a function that is passed into another function as an argument which can be invoked later inside the function.

## Synchronous callbacks
Synchronous means the code statements execute immediately after one another in a sequential manner.

```javascript
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
```

Here the callback is executing immediately and it is not waiting for any asynchronous operation to finish. That’s why it is synchronous callback.

## Asynchronous callbacks
If a callback is executing after an asynchronous operation has finished then it is an Asynchronous callback.

Let’s see one example where we will take an order and print it.

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

Here in the `takeOrder` function, the `setTimeout` will run after 1 sec, and by that time the `console.log` statement has already executed therefore printed value of order as `undefined`.

Now we can resolve this issue if we can log our message to console only after the data has returned from `takeOrder`. This can be done by passing a callback function to `takeOrder` which will be invoked inside `takeOrder` function.

```javascript
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
```

Here after 1 second the callback function will be called and the console statement will get executed with the correct order value.

> Note: The output of `takeOrder` function may differ in your case as we are using `Math.random()` to decide order value.

## Handling errors with callbacks
We can pass different callbacks for both success and failure scenarios.

```javascript
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);
    }
);
```

## Nested callbacks
Let’s see the order process one by one.

```javascript
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);
        })
    })
});
```
Output
```
Order is for: Coffee
Coffee is prepared
Coffee is served
```

Here `makeOrder` is called when response from `takeOrder` comes. Similarly `serveOrder` is called when response from `makeOrder` comes. Here we are nesting callbacks inside one another to execute functions in a sequence.

If the nesting of callbacks increases then it is called a **Callback hell**, where it is difficult to manage the callbacks and it reduces the readability of the code. Take a look at a sample callback hell.

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

This callback hell can be fixed by using [promise](https://jscurious.com/a-brief-guide-to-promises-in-javascript/) and [async/await](https://jscurious.com/understanding-async-and-await-in-javascript/).

There are some built in methods available in JavaScript that accepts callback as argument.

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

Let’s see some other methods that accept callback.
`Array.filter()`, `Array.reduce()`, `Array.find()`, `Array.sort()`, `Array.forEach()`, `setInterval()`, `addEventListener()`, `Promise.then()`, `Promise.catch()` etc.

## You may also like
* [A brief guide to Promises in JavaScript](https://jscurious.com/a-brief-guide-to-promises-in-javascript/)
* [Understanding async and await in JavaScript](https://jscurious.com/understanding-async-and-await-in-javascript/)
* [20 JavaScript Shorthand Techniques that will save your time](https://jscurious.com/20-javascript-shorthand-techniques-that-will-save-your-time/)

***Thanks for you time***
Find more of my writings on web development blogs at [jscurious.com](https://jscurious.com)