Callback Functions - JavaScript Core Concepts
Tags: codenewbie, javascript, beginners, tutorial
Published: 2022-10-26 16:38:36

The **Section 2:** _**Functions & Methods**_ of my **JavaScript Core Concepts** Series is divided into 6 Parts:

Part 1 Functions
Part 2 Classes
Part 3 Methods
**Part 4 Callback Functions**
Part 5 Scope
Part 6 Hoisting

## Callback Functions
### Part 1 What is a Callback Function?
= `Callback`: Name of a JS Function Convention 
→ Not a tool w/ unique functionality 

_Here are a few definitions:_

1. Function executed
= At end of execution of another function

2. Function passed into another Function as an Argument 
= To be executed later

3. Function that runs asynchronously

_Functions = Objects in JS_
= They can take Functions as Arguments
→ & Can be returned by other Functions

_Difference between Callbacks & most Functions_
= Callbacks do not immediately return some result 
→ They take time to product a result

#### Higher-Order Function
= Function that takes other functions as arguments
→ Function being passed in: Called a Callback Function

##### Code Example
```
const button = document.querySelector(‘button’)
button.addEventListener(‘click’, function(e) {
	this.classList.add(‘clicked’)
})
```
= JS listening for `click` event on button
→ Only calls the function in 2nd argument if event is detected

…

### Part 2 What is the purpose of a Callback Function?
1. Store things to do at later time 
= Order in which events occur: Does not work top-to-bottom
→ Skips around depending on when things complete

2. Dealing with tasks that get dispatched
= Go off and do something in the background 
→ Then, complete successfully or abort due to failure 

Callbacks are used in 2 different ways:
#### 1st Way: Synchronous Functions 
= Code is synchronous
→ If executes top-to-bottom, left-to-right, sequentially 
→ Waiting until 1 line of code finishes 
Before next line begins 
→ Process continues until last line of code is executed

##### Callbacks in Synchronous Functions 
= When want a part of code to be easily swapped w/ something else

###### Code Example
```
const numbers = [10, 11, 19, 40]
const getLessThanFifteen = num => num < 15
const getMoreThanTwenty = num => num > 20 

const lessThanFifteen = numbers.filter(getLessThanFifteen)

const moreThanTwenty = numbers.filter(getMoreThaTwenty)
```

##### Normal vs Async Functions
_Normal Functions_
= Allow you to use its return value

_Async Functions that use callbacks_
= Don’t return anything straight away

_Waiting for Response_
= Don’t want program to pause
→ So you store the code that should run afterwards
Inside a Function: Called a Callback Function 

#### 2nd Way: Asynchronous Functions
= Takes some time, happens in the future, not right now
→ JS needs to wait for something to complete
→ Will run rest of tasks given to it: While waiting

##### Code Example
= Asynchronous Function that takes a Callback to execute at later time
```
const twentySecondsLater = () => console.log(‘20 seconds passed!’)


setTimeout(twentySecondsLater, 20000)
console.log(‘Start!’)
```
= JS executes `setTimeout`
→ Then it waits for 20 seconds
→ And then logs ‘20 seconds passed!’

= Same time as waiting for `setTimeout` to complete in 20 seconds
→ JS executes `console.log(“Start!”)

…

### Part 3 How do you create a Callback?

= There are 2 ways to create Callbacks:

#### 1st Way: Anonymous Functions
1. Pass Callback Function Definition as an Argument

2. Define it in the Function Call

3. To do this, you pass in `callback` as the last Parameter of the Function

4. Then the Callback Function itself is defined in the 2nd Argument during the Function Call

##### Code Example 
```
function createEvent(date, callback) {
	console.log(`The event on ${date} has been created.`);
	callback();
}

createEvent(“September 22nd, 2022”, function() {
	console.log(`The event is being displayed.`)
})
```
	
#### 2nd Way: Named Functions 
1. Pass reference to Callback as an Argument

2. Or you can define the Callback Function elsewhere
= & Pass its reference as the 2nd Argument during the Function Call

3. You can also pass in any amount of arguments that the callback may need
= & Arguments passed into Callbacks
→ Make their way through to the Callback

##### Code Example 
```
function createEvent(date, callback) {
        console.log(`The event on ${date} has been created.`);
        callback();
}

function displayEvent(){
	console.log(`The event is being displayed.`);
}

createEvent(‘September 22nd, 2022’, displayEvent);
```

…

### Part 4 What do Callbacks look like in-action?
= Asynchronous Callbacks are useful as a *Solution* to **Blocking Behavior**

= Usually used when there is a transfer of data when doing I/O
→ ie Downloading things, reading files, talking to database, etc. 

#### Callback Queue 
= Everything in the Stack is ran before moving onto the Callback Queue 
→ Anything in a `setTimeout()` is ran with the Callback Queue
→ This means that even if something in the Callback Queue is never completed, the code keeps running

***Is the Callback Queue for all Callbacks or only Async Callbacks?***

#### Common Use Cases
1. When an event fires
= Event listeners 
ie `addEventListener`

2. After AJAX Calls
= jQuery’s ajax method 
ie `jQuery.ajax`

3. After reading or writing to files 
= Node, ExpressJS
ie `fs.readFile`

#### Purpose of Callbacks
= Ensure response of Function is received/finished executing
→ Before executing other code

##### Example Use Case
= Make Requests to an API
→ Need to wait to receive a Response from Server
To act based on Response
→ Do not know if API Request is going to be successful

###### Code Example
```
T.get(’search/tweets’, params, function(err, data, response) {
	if(!err){
	// What to do if API request successfully executes
	} else {
		console.log(err);
	}
})
```
= After Response received
→ Callback is invoked
→ Twitter will either send an `err` Object
Or a `response` Object back to us 

= Conditional w/in Callback 
→ Uses Information 
To determine if Request was successful or not 
Then act accordingly 

…

### Part 5 What are the problems with Callbacks?

The biggest problem with Callbacks is **Callback Hell**

#### What is Callback Hell?
= Multiple Callbacks nested after each other 
→ ie Doing an asynchronous activity 
That depends on previous asynchronous activity

##### Example Scenario
= Usually, Callback Hell is found in the Backend
→ While using Node 
→ Rare to see Callback Hell in Frontend JavaScript

= Pyramid shape with numerous `})`s at the end
→ Result of attempts to write JS so execution occurs chronologically
→ In JS, what occurs on 1st line will not necessarily finish before code in next line starts running
ie Async functions, `setTimeout()`s (which get ran after the call stack)

##### Why are Nested Callbacks bad?
= Code much more difficult to read 

##### What is the solution to Callback Hell?

= To prevent Callback Hell, you can do these things:

###### 1. Write Shallow Code
_#1 Do not nest Anonymous Functions_
= Name all Functions
→ Use Functions through reference to Names 
→ Rather than writing out elaborate logic of anonymous function	
→ Code will be easier to understand → B/c descriptive Names

_If exceptions occur_
= Have Stack Traces w/ Function Names
→ Bugs are easier to investigate

_#2 Place all Functions at top-level program (‘below the fold’)_
= Take advantage of Function Hoisting
→ Move all Functions to bottom of File
→ Then, move into another File: When & If the load demands 

###### 2. Modularize
_#1 Write small Modules_
= That each do 1 thing 
→ Compile them into other Modules that do a bigger thing
→ ie Split code into couple of Files

_#2 Isolated Files_
= Used by loading them through a relative `require()`
→ Then, can move Functions into standalone Module

_Code Example_
= Create a new File for a series of Functions 
→ Performing related functionality

**ie** Module named `useruploader.js`

```
module.exports.create = userCreate

function userSubmit (submitEvent) {
	var name = document.querySelector(‘input’).value
	request({
		uri: “http://example.com/upload”,
		body: name,
		method: “POST”
	}, postResponse)
}

function postResponse (err, response, body) {
	var statusMessage = document.querySelector(‘.status’)
	if (err) return statusMessage.value = err
	statusMessage.value = body 
}
```

#### `module.exports`
= Example of Node.js Module System 
→ Works in Node, Electron & Browser

##### Benefit of `module.exports`
= This style of Modules is good because it works everywhere
→ Easy to understand
→ Does not require complicated config files or scripts

##### Using `module.exports` Modules
= After File is created
→ You need to require it 
→ & Use it in your application specific code

###### Code Example
```
var userUploader = require(‘useruploader’)
document.querySelector(‘form’).onsubmit = userUploader.submit 
```

#### Benefits of Modularising
##### 1. Comprehensibility
= Code required in app is only 2 lines
→ Allows new devs to more easily understand you code 
→ Won’t need read through details of all Functions w/in Module: When trying to grasp what Program is trying to do

##### 2. Error-handling, test-writing, creating a stable and documented public API

##### 3. Refactoring

##### 4. Reuse
= W/o duplicating code 
→ Can easily be shared on Github or npm

#### How do you create good Modules?
##### 1. Move repeatedly used code into a Function 

##### 2. When Function/group of Functions gets large enough 
= Move them into another File 
→ Expose them using `module.exports`
→ Which can be loaded w/ a relative require

##### 3. Code that can be used across multiple projects
= Give it a Read.me, tests, and `package.json`
→ Public it to Github & npm 

##### 4. A Good Module
= Small & focuses on 1 problem

##### 5. Module Should Not
= Have > 1 level of nested Folders full of JS Files
→ If it does: It is likely doing too many things

##### 6. Reference Examples of Good Modules 
= Get a good idea of what they look like

##### 7. If Module takes > a few minutes to understand
= Not Good

…

### Part 6 How should Callbacks be used?
= Write Stable Code
= Handle Every Error 
→ You should handle every single error
→ In Every One of your Callbacks

#### How can you handle every error?
##### a. Plan on errors always happening
= Can never know when Errors happens
→ Must make code stable

##### b. Node.js Style 
= 1st Argument to Callback
→ Always reserved for an Error
→ Use `error` as 1st Argument Convention 
→ Instead of adding it as the 2nd Argument

= Reminds you to handle your errors 

##### c. Code Linters 
= Help remind you to handle Callback Errors
→ Show you every Callback in your code 
→ With an Unhandled Error 

#### Types of Errors
##### #1 Syntax Errors
= Caused by Programmers 
→ Usually caught when trying to 1st run program 

##### #2 Runtime Errors
= Caused by Programmer
→ Code ran, but had a bug that caused something to mess up 

##### #3 Platform Errors
= Caused by 
→ ie Invalid File Permissions, Hard Drive Failures, no Network Connection etc.

...

### Resources for Further Exploration:
[JavaScript: What the heck is a Callback? By Brandon Morelli](https://codeburst.io/javascript-what-the-heck-is-a-callback-aba4da2deced)

[Callback Hell: A guide to writing asynchronous JavaScript programs](http://callbackhell.com/)

[What the heck is the event loop anyway? | Philip Roberts | JSConf EU](https://youtu.be/8aGhZQkoFbQ)