Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(odin): add new content #800

Merged
merged 2 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
### Introduction

Asynchronous code can become difficult to follow when it has a lot of things going on. `async` and `await` are two keywords that can help make asynchronous read more like synchronous code. This can help code look cleaner while keeping the benefits of asynchronous code.

For example, the two code blocks below do the exact same thing. They both get information from a server, process it, and return a promise.

```javascript
function getPersonsInfo(name) {
return server.getPeople().then(people => {
return people.find(person => { return person.name === name });
});
}
```

```javascript
async function getPersonsInfo(name) {
const people = await server.getPeople();
const person = people.find(person => { return person.name === name });
return person;
}
```

The second example looks much more like the kind of functions you are used to writing. However, did you notice the `async` keyword before the function declaration? How about the `await` keyword before `server.getPeople()`?

If you'd like to try running these functions on your own, paste the following code block representing a server before the function definitions. How this "server" works is not important and is just an abstraction. The goal here is so that you can see that both functions behave exactly the same and return a promise.

```javascript
const server = {
people: [
{
name: "Odin",
age: 20,
},
{
name: "Thor",
age: 35,
},
{
name: "Freyja",
age: 29,
},
],

getPeople() {
return new Promise((resolve, reject) => {
// Simulating a delayed network call to the server
setTimeout(() => {
resolve(this.people);
}, 2000);
});
},
};
```

### Lesson overview

This section contains a general overview of topics that you will learn in this lesson.

- Explain how you declare an `async` function
- Explain what the `async` keyword does
- Explain what the `await` keyword does
- Explain what an `async` function returns
- Explain what happens when an error is thrown inside an `async` function
- Explain how you can handle errors inside an `async` function

### The async keyword

The `async` keyword is what lets the JavaScript engine know that you are declaring an asynchronous function. This is required to use `await` inside any function. When a function is declared with `async`, it automatically returns a promise; returning in an `async` function is the same as resolving a promise. Likewise, throwing an error will reject the promise.

An important thing to understand is `async` functions are just syntactical sugar for `promises`.

The `async` keyword can also be used with any of the ways a function can be created. Said differently: it is valid to use an `async` function anywhere you can use a normal function. Below you will see some examples that may not be intuitive. If you don't understand them, come back and take a look when you are done with the assignments.

```javascript
const yourAsyncFunction = async () => {
// do something asynchronously and return a promise
return result;
}
```

```javascript
anArray.forEach(async item => {
// do something asynchronously for each item in 'anArray'
// one could also use .map here to return an array of promises to use with 'Promise.all()'
});
```

```javascript
server.getPeople().then(async people => {
people.forEach(person => {
// do something asynchronously for each person
});
});
```

### The await keyword

`await` does the following: it tells JavaScript to wait for an asynchronous action to finish before continuing the function. It's like a 'pause until done' keyword. The `await` keyword is used to get a value from a function where you would normally use `.then()`. Instead of calling `.then()` after the asynchronous function, you would assign a variable to the result using `await`. Then you can use the result in your code as you would in your synchronous code.

### Error handling

Handling errors in `async` functions is very easy. Promises have the `.catch()` method for handling rejected promises, and since async functions just return a promise, you can call the function, and append a `.catch()` method to the end.

```javascript
asyncFunctionCall().catch(err => {
console.error(err)
});
```

But there is another way: the mighty `try/catch` block! If you want to handle the error directly inside the `async` function, you can use `try/catch` just like you would inside synchronous code.

```javascript
async function getPersonsInfo(name) {
try {
const people = await server.getPeople();
const person = people.find(person => { return person.name === name });
return person;
} catch (error) {
// Handle the error any way you'd like
}
}
```

Doing this can look messy, but it is a very easy way to handle errors without appending `.catch()` after your function calls. How you handle the errors is up to you, and which method you use should be determined by how your code was written. You will get a feel for what needs to be done over time. The assignments will also help you understand how to handle your errors.

### Practice

Remember the Giphy API practice project? (If not, you should go back and complete the API lesson). We are going to convert the promise based code into `async/await` compatible code. Here's a refresher of the code we are starting with:

```javascript
<script>
const img = document.querySelector('img');
fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'})
.then(function(response) {
return response.json();
})
.then(function(response) {
img.src = response.data.images.original.url;
});
</script>
```

Since `await` does not work on the global scope, we will have to create an `async` function that wraps our API call to Giphy.

```javascript
<script>
const img = document.querySelector('img');

async function getCats() {
fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'})
.then(function(response) {
return response.json();
})
.then(function(response) {
img.src = response.data.images.original.url;
})
}
</script>
```

Now that we have a function that is asynchronous, we can then start refactoring from using promises to using `await`:

```javascript
<script>
const img = document.querySelector('img');

async function getCats() {
const response = await fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'});
response.json().then(function(response) {
img.src = response.data.images.original.url;
});
}
</script>
```

Since `response` is still the same object we have passed to the `.then()` block at the start, we still need to use the `.json()` method, which in turn returns a promise. Because `.json()` returns a promise, we can use `await` to assign the response to a variable.

```javascript
<script>
const img = document.querySelector('img');

async function getCats() {
const response = await fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'});
const catData = await response.json();
img.src = catData.data.images.original.url;
}
</script>
```

To use this function, we just need to call it with `getCats()` in our code.

```javascript
<script>
const img = document.querySelector('img');

async function getCats() {
const response = await fetch('https://api.giphy.com/v1/gifs/translate?api_key=YOUR_KEY_HERE&s=cats', {mode: 'cors'});
const catData = await response.json();
img.src = catData.data.images.original.url;
}
getCats();
</script>
```

This code will behave exactly like the code from the last lesson; it just looks a bit different after refactoring. `async/await` are very useful tools when it comes to cleaning up asynchronous JavaScript code. It is important to remember `async/await` are just promises written in a different way. Do the assignments below, and dive deeper into the understanding of `async/await`.

### Assignment

<div class="lesson-content__panel" markdown="1">

1. Read this [Async and Await article](https://javascript.info/async-await) for a solid introduction to async/await. This [Async and Await examples article](https://codeburst.io/javascript-es-2017-learn-async-await-by-example-48acc58bad65) also has some good examples of its use.
2. Watch this [Async and Await video by Wes Bos](https://www.youtube.com/watch?v=9YkUCxvaLEk) for a good overview on async/await and its purpose, along with a special trick.

</div>

### Knowledge check

This section contains questions for you to check your understanding of this lesson. If you’re having trouble answering the questions below on your own, review the material above to find the answer.

- [How do you declare an `async` function?](#the-async-keyword)
- [What does the `async` keyword do?](#the-async-keyword)
- [What does the `await` keyword do?](#the-await-keyword)
- [What is returned from an `async` function?](https://javascript.info/async-await#summary)
- [What happens when an error is thrown inside an `async` function?](https://javascript.info/async-await#error-handling)
- [How can you handle errors inside an `async` function?](https://javascript.info/async-await#error-handling)

### Additional resources

This section contains helpful links to other content. It isn't required, so consider it supplemental.

1. This [Change promises to async/await video](https://www.youtube.com/watch?v=COKdtOgopWQ) is an example of how you can change callbacks, to promises, to async/await.
2. This [Promises, Async and Await video](https://www.youtube.com/watch?v=vn3tm0quoqE) gives a comprehensive view of Promises, async, and await.
3. For a more interactive explanation and example, try a [Scrim on async and await](https://scrimba.com/scrim/crd4eMc6?embed=odin,mini-header,no-next-up).
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
### Introduction

Since JavaScript is the language of the web, there are some functions that by necessity are going to take a decent amount of time to complete, such as fetching data from a server to display on your site. For this reason, JavaScript includes support for asynchronous functions, or to put it another way, functions that can happen in the background while the rest of your code executes.

### Lesson overview

This section contains a general overview of topics that you will learn in this lesson.

- Explain what a callback is
- Explain what a promise is
- Explain the circumstances under which promises are better than callbacks
- Explain what the `.then()` function does

### Callbacks

In the recent past, the way that these were most commonly handled were with __callbacks__, and even now they are still used quite a lot in certain circumstances.

> A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action. [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function)

Callbacks are functions that get passed into other functions. For example:

```javascript
myDiv.addEventListener("click", function(){
// do something!
})
```

Here, the function `addEventListener()` takes a callback (the "do something" function) and then calls it when `myDiv` gets clicked.

You will likely recognize this pattern as something that happens _all the time_ in JavaScript code. Unfortunately, though they are useful in situations like the above example, using callbacks can get out of hand, especially when you need to chain several of them together in a specific order. The rest of this lesson discusses patterns and functions that will help keep you out of [Callback hell](http://callbackhell.com/).

Take a moment to skim through this [Callback article](https://github.com/maxogden/art-of-node#callbacks) before moving on. Or, if you prefer to watch a video of [Callback functions](https://www.youtube.com/watch?v=QRq2zMHlBz4).

### Promises

There are multiple ways that you can handle asynchronous code in JavaScript, and they all have their use cases. Promises are one such mechanism, and they're one you will see somewhat often when using other libraries or frameworks. Knowing what they are and how to use them is quite useful.

Essentially, a promise is an object that might produce a value at some point in the future. Here's an example:

Lets say `getData()` is a function that fetches some data from a server and returns it as an object that we can use in our code:

```javascript
const getData = function() {
// go fetch data from some API...
// clean it up a bit and return it as an object:
return data
}
```

The issue with this example is that it takes some time to fetch the data, but unless we tell our code that, it assumes that everything in the function happens essentially instantly. So, if we try to do this:

```javascript
const myData = getData()
const pieceOfData = myData['whatever']
```

We're going to run into trouble because when we try to extract `pieceOfData` out of the returned data, the function `getData()` will most likely still be fetching, so `myData` will not be the expected data, but will be `undefined`. Sad.

We need some way to solve this problem, and tell our code to wait until the data is done fetching to continue. Promises solve this issue. We'll leave learning the specific syntax for the articles you're about to read, but essentially Promises allow you to do this:

```javascript
const myData = getData() // if this is refactored to return a Promise...

myData.then(function(data){ // .then() tells it to wait until the promise is resolved
const pieceOfData = data['whatever'] // and THEN run the function inside
})
```

Of course, there are many more occasions where one would want to use Promises beyond fetching data, so learning these things now will be very useful to you.

### Assignment

<div class="lesson-content__panel" markdown="1">

1. Read this [Promises article](https://davidwalsh.name/promises). It's a good starting place and it's short and to the point.
2. Watch this [Promises video](https://youtu.be/DHvZLI7Db8E). It's a good place to get a feel for how one might actually use promises in the wild.
3. Watch this [What is Event Loop? video](https://www.youtube.com/watch?v=8aGhZQkoFbQ) to understand how asynchronous code works in JavaScript.
4. Read [Chapter 2: Callbacks](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch2.md) and [Chapter 3: Promises](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch3.md) from `You Don't Know JS`. In _Chapter 2_, the author explains the problems with callbacks and why callback hell will be your worst enemy (hint: it's the inversion of control and non-linear nature of callbacks). In _Chapter 3_, you go __deep__ into the how and why of promises. This chapter is not the easiest read, but you'll be a promise professional if you take the time to properly digest it. It's worth the effort.

</div>

### Knowledge check

This section contains questions for you to check your understanding of this lesson. If you’re having trouble answering the questions below on your own, review the material above to find the answer.

- [What is a callback?](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function)
- [What is a promise?](#promises)
- [When should you use promises over callbacks?](http://callbackhell.com/)
- [What does the `.then()` function do?](https://davidwalsh.name/promises)

### Additional resources

This section contains helpful links to other content. It isn't required, so consider it supplemental.

1. This [Callback article](https://www.sitepoint.com/demystifying-javascript-closures-callbacks-iifes/) is another useful article about Callback functions in JavaScript.
2. The [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) for Promises. It might not be the best resource for _learning_ all about them, but once you've read a more friendly article or tutorial, this will probably be the place you return to for a refresher.
3. These [ES6 Promises video](https://www.youtube.com/watch?v=vQ3MoXnKfuQ), [Promises by The Net Ninja](https://www.youtube.com/watch?v=yswb4SkDoj0) and [Promises by ColorCode](https://www.youtube.com/watch?v=TnhCX0KkPqs) are nice introductions to Promises if you need more repetition and additional information.
4. This [Understanding JavaScript Promises Tutorial](https://www.digitalocean.com/community/tutorials/understanding-javascript-promises) is another good introduction.
5. For a more interactive explanation and example, try a [Scrim on asynchronous coding](https://scrimba.com/scrim/cof4e4fb797a2d0a236ea38ce?embed=odin,mini-header,no-next-up).
Loading
Loading