feat(resources): split up topics and languages

This commit is contained in:
Jean-Philippe Sirois
2020-05-27 02:42:39 -04:00
parent 8fba0edc4f
commit 135452bd4b
35 changed files with 86 additions and 55 deletions
@@ -0,0 +1,170 @@
---
authors:
- "ddivad#0001"
- "veksen#1060"
created_at: "2019/10/01"
updated_at: 2020/05/20
title: Async/Await
recommended_reading:
- javascript/promises/intro
---
## Async/Await
Async/Await is another way to handle the calling of asynchronous code and is built on top of Promises. It makes it possible to write asynchronous code that feels synchronous.
**Its usage is equivalent to resolving a promise with `.then()`**.
It is made up of 2 keywords as the name suggests: `async` and `await`. These need to be used together for this method to work.
## Async
The `async` keyword is used to show that the function is going to return a promise. **Any return values from the function will be converted to a promise automatically**, if they are not already.
```js
async function getWeather() {
return "sunny";
}
getPromise();
// Promise<"sunny">
```
This basic example will return a promise with the value of `getWeather`.
## Await
The `await` keyword is used to wait until a promise has executed and fetches the result. In order to use the `await` keyword, you **need** to be inside an `async` function.
```js
async function checkWeather() {
const weather = await getWeather();
console.log(weather); // "sunny"
}
```
This code will call the `getWeather()` function from above and will wait on that line until the promise returned from the `async` function has returned.
Another example to demonstrate this is if we extended the `getWeather()` function from above to add a 5 second delay.
```js
async function getWeather() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("sunny"), 5000);
});
const weather = await promise; // Execution waits here until promise resolves
console.log(weather); // "sunny"
}
```
## Error Handling
As with Promises, if the Promise returns with an error, it will affect the `await` call that triggered it. When using Promises without Async / Await, the `.catch()` syntax is used, and this also exists with Aysnc / Await using the `try...catch` syntax. This can be demonstrated by making our `foo()` function throw an error.
```js
async function foo() {
throw new Error("An Error Occurred");
}
```
This would be handled using Aysnc / Await like so:
```js
async function getData() {
try {
let data = await foo();
console.log(data);
} catch (err) {
console.error(err); // err: An Error Occurred
}
}
```
## Beginner Mistakes
As mentioned in the [intro](./intro.md), Promises are the highest source of confusion for beginners. Async / Await adds another layer on top of Promises, and comes with its own pitfalls.
`await` will **only** work if the function you try to add `await` to is `async`. Using `await` in top level code will not work (yet).
```js
let weather = await getWeather(); // syntax error
```
To get around this issue, you can use an declare asynchronous function anonymously, if needed:
```js
(async () => {
let weather = await getWeather();
console.log(weather); // "sunny"
})();
```
Top-Level-Await is something that _may_ get added to Javascript in the future, but for now wrapper functions like above are needed for this functionality.
## Real World Example
Here is a real function that gets character information from the Rick and Morty API.
You can try it in your browser if you want to test it out.
```js
async function getCharacters() {
const response = await fetch(`https://rickandmortyapi.com/api/character`);
const data = await response.json();
return data.results;
}
// or, mixed
async function getCharacters() {
const data = await fetch(
`https://rickandmortyapi.com/api/character`
).then((res) => res.json());
return data.results;
}
(async () => {
try {
let characters = await getCharacters();
console.log(characters); // (20) [{...}, {...}, {...}]
} catch (err) {
console.error(err);
}
})();
```
In this example, we are querying real data from the Rick & Morty API. This API has a lot of information regarding Rick & Morty, but here, we are trying to retrieve all the characters.
- The first thing we do is use `fetch` to retrieve the data from the API. `fetch` is a built in function in web browsers to do http requests, and returns a Promise by default. We `await` the result of this.
- When we get the result, we need to get the `JSON` value of the data. To do this, the `.json()` method from fetch is used. We then return the results.
- As `await` can only be used in an `async` function, we use the method from above to make this work. As `getCharacters()` returns a Promise due to it being `async`, we `await` the result. We surround this in a `try...catch` in case fetch returns an error. Then, if no error is returned, `characters` contains the information we want, and is logged to the console. If `getCharacters()` returns an error, that error is also logged.
### Let's also look at an example from Discord.js:
```js
client.on("message", (msg) => {
if (msg.author.bot) return;
if (msg.content === "ping") {
const message = await msg.channel.send("pong");
message.react("⚠️");
}
})
```
## Comparision with default Promises
Below is the same code implemented without using Async / Await as a comparision. Here, you can see the differences between the two methods, and how Aysnc / Await makes the code appear in a _more synchronous_ pattern, and can be clearer to follow.
```js
function getCharacters() {
return fetch(`https://rickandmortyapi.com/api/character`)
.then((res) => res.json())
.then((res) => res.results);
}
getCharacters()
.then((characters) => {
console.log(characters); // (20) [{...}, {...}, {...}]
})
.catch((err) => console.error(err));
```
@@ -0,0 +1,63 @@
---
authors:
- "veksen#1060"
created_at: "2020/05/20"
title: Converting a callback
recommended_reading:
- javascript/promises/intro
- javascript/promises/async-await
---
It's still pretty common to be forced to use an API that doesn't support promises. While a promise API is often preferred, it's not always available.
Before anything check:
- If your library might support both callbacks and API, in the documentation, or README from Github
- If there is not another library that does the same thing, but supports promises.
## From a callback
Let's look at a conventional, but fictional callback API:
```js
getWeather("Los Angeles", (error, result) => {
if (err) throw err;
console.log(result); // "sunny"
});
```
## To a promise
If we want to use it as a promise, we'll need to wrap a promise around it:
```js
function getWeatherAsync(city) {
return new Promise((resolve, reject) => {
getWeather(city, (error, result) => {
if (err) reject(err);
resolve(result);
});
});
}
```
Which we can now use:
```js
getWeatherAsync("Los Angeles")
.then((weather) => {
console.log(weather);
})
.catch((error) => {
console.log(error);
});
// or using async/await
const weather = await getWeatherAsync("Los Angeles").catch((error) => {
console.log(error);
});
console.log(weather);
```
@@ -0,0 +1,112 @@
---
authors:
- "Xetera#0001"
- "veksen#1060"
created_at: 2019/07/26
updated_at: 2020/05/20
title: Introduction to Promises
recommended_reading:
- javascript/callbacks/intro
- javascript/es6/arrow-functions
---
## A Promise to Keep
A `Promise` in Javascript represents an action that has already started, but one that will be
completed at a later time. Much like in real life, when you create a promise, you are expected
to fulfill that promise. However, sometimes things go wrong where you can no longer fulfill
a promise you made. This is essentially the main idea behind how promises work in javascript.
## Basics
When you create a Promise or call a function that returns a Promise in Javascript, you're left
with an object that can either resolve into the actual value that you were promised, or it
can reject and leave you with an error for why that promise failed.
We can access these values using the `.then` and `.catch` methods on the `Promise` object respectively.
## A Simple Example
First, let's explore a bit of a made-up example. Imagine we have a promise-returning function
called `getMembers` that retrieves all the members in a discord server. When we execute this
function we see the following result.
```js
const members = getMembers("The Programmers Hangout");
console.log(members); // Promise {<pending>}
```
Normally, we would have expected to see an array of all the members but it takes time to
get all the information about members so we're instead returned a Promise of members, rather
than the members themselves.
In order to access this information, we'll have to call the `.then` method on our `members` object
to access the actual members like so.
```js
getMembers("The Programmers Hangout").then((members) => {
console.log(members); // (32k) [{...}, {...}, {...}]
});
```
This way we are able to make sure that we only try to `console.log` when the `getMembers` function has resolved and ready to be used.
## Beginner Mistakes
Promises are possibly the #1 most common source of confusion for beginners. In order
to avoid falling in pitfalls yourself, you have to remember 2 things about Javascript when
working with promises.
1. Javascript does not wait.
2. No seriously, Javascript won't wait for your promises!
You may have tried doing something like this before.
```js
// Incorrect code, don't copy!
let results;
getWeather("Los Angeles").then((weather) => {
results = weather;
});
console.log(results); // undefined
```
Why is `results` undefined? Because **Javascript doesn't wait**. Whenever a Promise is created,
your code will continue to run until there's no more code left in the stack. Only then
will javascript try to run the `.then` callback of a Promise. Even if your Promise resolves
immediately you are going to have to wait until you've run all the code in the stack before
your `.then` callback has a chance to start running. This is due to the way the event loop works,
you can watch [this amazing talk](https://youtu.be/8aGhZQkoFbQ) on it to learn more.
In order to fix this problem we need to move the `console.log` inside the `.then` callback like so:
```js
getWeather("Los Angeles").then((weather) => {
console.log(weather); // Sunny, probably
});
```
Outlining this one again, because it's very common, is to attempt to use the value of a promise, but not resolving it:
```js
// Incorrect code, don't copy!
const weather = getWeather("Los Angeles");
console.log(weather); // Promise {<pending>}
```
## Real World Example
Here is a real function that gets character information from the Rick and Morty API.
You can try it in your browser if you want to test it out.
```js
function getCharacters() {
return fetch(`https://rickandmortyapi.com/api/character`)
.then((response) => response.json())
.then((response) => response.results);
}
getCharacters().then((characters) => {
console.log(characters); // (20) [{...}, {...}, {...}]
});
```
@@ -0,0 +1,72 @@
---
authors:
- "Xetera#0001"
created_at: "2019/07/26"
title: Simplifying Promises
---
The first naive attempt, using new Promise for something that already returns a promise.
```js
function doAsync(number) {
return new Promise(function (resolve, reject) {
doDatabase().then(function (dbResult) {
otherDbFunction(dbResult).then(function (secondResult) {
resolve(secondResult + 10);
});
});
});
}
```
Turns out you don't need new Promise if you're working with a function that
already returns a promise, you can just return the original thing.
```js
function doAsync(number) {
return doDatabase().then(function (dbResult) {
otherDbFunction(dbResult).then(function (secondResult) {
return secondResult + 10;
});
});
}
```
You also don't have to nest `.then` functions, the whole point of promises
is that they allow you to chain them sequentially.
```js
function doAsync(number) {
return doDatabase()
.then(function (dbResult) {
return otherDbFunction(dbResult);
})
.then(function (secondResult) {
return secondResult + 10;
});
}
```
you also don't have to create a new function just to pass in one
variable, you can pass in the entire function itself to the then block
```js
function doAsync(number) {
return doDatabase()
.then(otherDbFunction)
.then(function (secondResult) {
return secondResult + 10;
});
}
```
And you don't need those returns if you just have ES6 arrow functions
```js
const doAsync = (number) =>
doDatabase()
.then(otherDbFunction)
.then((secondResult) => secondResult + 10);
```
Wow, that last one looks a lot cleaner to me than the first. Keeping that in mind, maybe we could be making some of our other functions cleaner as well