Skip to content

Commit 8c0abfb

Browse files
committed
learn about async/await and async code execution in promises
1 parent 28a6628 commit 8c0abfb

File tree

2 files changed

+177
-15
lines changed

2 files changed

+177
-15
lines changed

Async-JS-Promises-and-Callbacks/README.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
| [Sync + Async Code - The Execution Order](#sync--async-code---the-execution-order) |
99
| [Multiple Callbacks and setTimeout(0)](#multiple-callbacks-and-settimeout0) |
1010
| [Getting Started with Promises](#getting-started-with-promises) |
11+
| [Asynchronous Code Execution in Promises](#asynchronous-code-execution-in-promises) |
1112
| [Chaining Multiple Promises](#chaining-multiple-promises) |
1213
| [Promise Error Handling](#promise-error-handling) |
1314
| [Promise States & "finally"](#promise-states--finally) |
15+
| [Async/Await](#asyncawait) |
1416

1517
## Understanding Synchronous Code Execution ("Sync Code")
1618

@@ -384,6 +386,24 @@ Readings:
384386

385387
- [JavaScript Promise and Promise Chaining](https://www.programiz.com/javascript/promise)
386388

389+
## Asynchronous Code Execution in Promises
390+
391+
Promises in JavaScript enable asynchronous behavior by leveraging the event loop and a concept called "callbacks." To understand how promises work asynchronously, let's break down the process:
392+
393+
1. **Creation of a Promise:** When you create a promise using the `new Promise()` constructor, you're defining a task that may take some time to complete. The promise has three possible states: pending, resolved, or rejected.
394+
395+
2. **Executor Function:** The Promise constructor takes an executor function as an argument. This function typically contains the code that performs the asynchronous task, like fetching data from a server. This function receives two parameters: `resolve` and `reject`. These are functions provided by JavaScript that allow you to signal that the task is completed (resolved) or encountered an error (rejected).
396+
397+
3. **Event Loop:** JavaScript uses an event loop to manage asynchronous operations. The event loop continuously checks the execution stack and the callback queue. When the execution stack is empty, the event loop picks tasks from the callback queue and executes them.
398+
399+
4. **Execution of Asynchronous Code:** When you perform an asynchronous operation, like making an HTTP request, the JavaScript engine doesn't wait for the result. Instead, it registers a callback function to be executed when the operation completes.
400+
401+
5. **Promise State Transition:** Inside the executor function, when the asynchronous task completes successfully, you call the `resolve` function, which transitions the promise's state from pending to resolved. If an error occurs, you call the `reject` function, transitioning the state to rejected.
402+
403+
6. **Consuming the Promise:** Outside the promise creation, you use the `.then()` method to attach a callback function. This callback function will be placed in the callback queue by the promise when the promise's state transitions to resolved. The event loop eventually picks up this callback and executes it, allowing you to work with the resolved value.
404+
405+
In summary, promises run code asynchronously by using the event loop and callbacks. When an asynchronous operation is encountered, the code continues to execute, and a promise is created to manage the outcome of that operation. The promise transitions between different states based on the outcome of the asynchronous task, and the callback registered with `.then()` is executed once the promise resolves.
406+
387407
## Chaining Multiple Promises
388408

389409
Let's now also wrap `navigator.geolocation.getCurrentPosition()` around promise object and [`then`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) demonstrate the promise chaining.
@@ -602,3 +622,140 @@ somePromiseCreatingCode()
602622
Readings:
603623

604624
- [JavaScript Promises – The promise.then, promise.catch and promise.finally Methods Explained](https://www.freecodecamp.org/news/javascript-promise-methods/)
625+
626+
## Async/Await
627+
628+
Promises are a crucial concept in JavaScript, especially in modern JavaScript which we're learning here. They're extensively used, even more so when dealing with async operations like HTTP requests. As you work on various projects involving async code, you'll frequently encounter promises.
629+
630+
Now, there's an alternative to this approach that modern JavaScript offers, which is quite important to grasp. This approach still involves promises but allows you to omit the `then` and `catch` methods. This makes the code resemble synchronous code more closely—similar to what you write without promises. This approach is known as [`async`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)/[`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await).
631+
632+
What is `async`/`await` all about? It's used only with functions, and those functions must be marked as `async`. ***By adding the `async` keyword before the function declaration, the function transforms into one that automatically returns a promise.*** This wrapping into a promise is done internally, even though you don't explicitly use the `return` statement. This is a subtle but significant change.
633+
634+
Adding the `async` keyword transforms the function into a promise without changing the way JavaScript works. Any call to `then` will now operate on this promise. Inside this wrapped promise, we gain access to the `await` keyword. Adding `await` in front of a promise makes the execution wait for that promise to resolve or reject. The next line of code only executes once the promise is resolved.
635+
636+
In essence, `async`/`await` doesn't alter JavaScript's non-blocking nature. Instead, it transforms the code to work with promises in a way that appears synchronous. It doesn't block code execution; it's more like code transformation that preserves JavaScript's asynchronous nature. So, you're reaping the benefits of more readable code without changing the core behavior of JavaScript.
637+
638+
```javascript
639+
const button = document.querySelector('button');
640+
641+
const getPosition = (opts) => {
642+
const promise = new Promise((resolve, reject) => {
643+
navigator.geolocation.getCurrentPosition(success => {
644+
resolve(success);
645+
}, error => {
646+
reject(error);
647+
}, opts);
648+
});
649+
return promise;
650+
};
651+
652+
const setTimer = (duration) => {
653+
const promise = new Promise((resolve, reject) => {
654+
setTimeout(() => {
655+
resolve('Done!');
656+
}, duration);
657+
});
658+
return promise;
659+
};
660+
661+
async function trackUserHandler() {
662+
// let positionData;
663+
const posData = await getPosition();
664+
const timerData = await setTimer(2000);
665+
console.log(timerData, posData);
666+
// .then(posData => {
667+
// positionData = posData;
668+
// return setTimer(2000);
669+
// })
670+
// .catch(err => {
671+
// console.log(err);
672+
// })
673+
// .then(data => {
674+
// console.log(data, positionData);
675+
// });
676+
677+
// setTimer(1000).then(() => {
678+
// console.log('Timer Done!');
679+
// });
680+
// console.log("Getting position...");
681+
}
682+
683+
button.addEventListener('click', trackUserHandler);
684+
```
685+
686+
Mentioning another example for more understanding.
687+
688+
Consider a scenario where you want to fetch user data from an API and then log the user's name. We'll first implement this using Promises and then refactor it using Async and Await.
689+
690+
**Using Promises:**
691+
692+
```javascript
693+
function fetchUserData() {
694+
return new Promise((resolve, reject) => {
695+
// Simulate fetching user data from an API
696+
setTimeout(() => {
697+
const userData = { id: 1, name: "John Doe" };
698+
resolve(userData);
699+
}, 1000);
700+
});
701+
}
702+
703+
fetchUserData()
704+
.then(user => {
705+
console.log(user.name);
706+
})
707+
.catch(error => {
708+
console.error("Error fetching user data:", error);
709+
});
710+
```
711+
712+
**Using Async and Await:**
713+
714+
```javascript
715+
async function fetchUserData() {
716+
return new Promise((resolve) => {
717+
setTimeout(() => {
718+
const userData = { id: 1, name: "John Doe" };
719+
resolve(userData);
720+
}, 1000);
721+
});
722+
}
723+
724+
async function logUserName() {
725+
try {
726+
const user = await fetchUserData();
727+
console.log(user.name);
728+
} catch (error) {
729+
console.error("Error fetching user data:", error);
730+
}
731+
}
732+
733+
logUserName();
734+
console.log("test");
735+
736+
// Output
737+
// test
738+
// John Doe
739+
```
740+
741+
In the second example using Async and Await:
742+
743+
1. We declare the `fetchUserData` function as `async` to indicate that it contains asynchronous operations.
744+
745+
2. Inside `fetchUserData`, we use a `setTimeout` to simulate fetching user data from an API. We return a promise that resolves with the user data.
746+
747+
3. The `logUserName` function is also declared as `async`.
748+
749+
4. Inside `logUserName`, we use the `await` keyword before calling `fetchUserData()`. This tells JavaScript to pause the execution of the function until the promise from `fetchUserData` resolves. This makes the code appear more synchronous, as if you're waiting for the result of a regular function call.
750+
751+
5. If the promise is resolved, the value returned from the promise is assigned to the `user` variable, and we can then log the user's name.
752+
753+
6. If an error occurs during the `fetchUserData` promise, the catch block will catch the error and log an error message.
754+
755+
In summary, `async` and `await` provide a cleaner and more intuitive way to work with asynchronous operations compared to handling callbacks and chaining promises. The code structure resembles synchronous code, making it easier to understand and maintain asynchronous workflows.
756+
757+
Readings:
758+
759+
- [How Async Javascript works (Callback Hell, Promises, Async Await, Call Stack and more)](https://www.youtube.com/watch?v=1Z7FjG--F20)
760+
761+
- [JavaScript async/await](https://www.javascripttutorial.net/es-next/javascript-async-await/)

Async-JS-Promises-and-Callbacks/summary-with-code/app.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,29 @@ const setTimer = (duration) => {
2727
return promise;
2828
};
2929

30-
function trackUserHandler() {
31-
let positionData;
32-
getPosition()
33-
.then(posData => {
34-
positionData = posData;
35-
return setTimer(2000);
36-
})
37-
.then(data => {
38-
console.log(data, positionData);
39-
});
40-
setTimer(1000).then(() => {
41-
console.log('Timer Done!');
42-
});
43-
console.log("Getting position...");
30+
async function trackUserHandler() {
31+
// let positionData;
32+
const posData = await getPosition();
33+
const timerData = await setTimer(2000);
34+
console.log(timerData, posData);
35+
// .then(posData => {
36+
// positionData = posData;
37+
// return setTimer(2000);
38+
// })
39+
// .catch(err => {
40+
// console.log(err);
41+
// })
42+
// .then(data => {
43+
// console.log(data, positionData);
44+
// });
45+
46+
// setTimer(1000).then(() => {
47+
// console.log('Timer Done!');
48+
// });
49+
// console.log("Getting position...");
4450
}
4551

4652
button.addEventListener('click', trackUserHandler);
47-
4853
// let result = 0;
4954

5055
// for (let i = 0; i < 100000000; i++) {

0 commit comments

Comments
 (0)