Learning Node.js — Part 4
Synchronous Programming → Blocking . Each statement in your code will executed one after the other. Each statement must wait until the previous statement has completed executing.
Asynchronous Programming → Non-Blocking (does not mean concurrent or multi-threaded). The programs we are building are single-threaded. Any program that is working with network access is dealing with async code.
Review — Set Up A New App
Starting a new application, cd into your desired path location and make a new folder: mkdir <app_name> . Change directory into this app type in terminal command: npm init — — yes to set up your package.json file. Next, make a new file in the folder, type in terminal command: touch index.js . Open this folder (code . if using VS Code) in your preferred text editor.
Function that we will call when the result of an asynchronous operation is ready. If we don’t use the callback and we immediately try to return a user, before the async function has completed, the return value will be undefined.
When we run the file in our terminal with command node index.js , the output will be:
Callback Hell or Christmas Tree Problem
When writing our code and implementing callback functions, our code can start to become very deeply nested when callbacks begin having callbacks.
The refactor to make this code more readable involves turning the anonymous callback functions into named functions:
Don’t need to call the function ‘()’, just pass the reference of the function:
Object that holds the eventual result of an asynchronous operation. The result is either a value or an error¹.Promises are a better way to deal with async code.
A Promise exists in 3 states:
- (1) Pending (a Promise always starts out in pending)
- (2) Resolved or Fulfilled (successfully completed and delivers a value)
- (3) Rejected (async function not completed successfully and result is an error).
Anywhere you have an async function that takes a callback, the function should return a Promise.
Promise results are passed through a chain of .then handlers called Promise Chaining. The .then() handler returns a promise. This handler gets the result of async operations. Another handler, .catch() catches any errors when the promise is rejected.
Create a new file: promise.js . To run these files, type command: node promise.js .
This code shows an async function where the promise is resolved:
The code below shows an async function where the promise is rejected:
Replacing Callbacks with Promises
In our index.js file, you can see that we have replaced our callback functions so that are functions now return a Promise:
getUser() returns a Promise now, so getUser now supplies us with the .then() and .catch() handlers. We can change our code as follows to consume the Promise returned by getUser():
- Still single threaded (one call stack and one memory heap). Not real concurrency(multi-threaded).
- Not waiting for async operation to complete…both ops are starting almost exactly at same time.
- Result will be available as array.
Set up a new file to test the next 3 examples out: promise-api.js :
If any of the promises in Promise.all is rejected, the Promise that is returned is rejected and won’t return the array:
Promise.race() method returns a promise that fulfills or rejects as soon as one of the promises in an iterable fulfills or rejects, with the value or reason from that promise². The result of Promise.race() is NOT an array, it’s the value of the FIRST fulfilled promise:
Async and Await
Write Asynchronous code like Synchronous code. Async/await are built on top of Promises. JS engine converts async/await code into code that looks more like our Promises code above. (Await does not mean it is blocking!)
We can refactor our index.js file with async/await:
This Promise, once resolved doesn’t result in a value (displayCommits(): Promise<void>) :
Don’t have .catch() handler in async and await for errors. We instead must use the try/catch block:
- Node.js Tutorial for Beginners | Programming with Mosh | “https://www.youtube.com/watch?v=TlB_eWDSMt4&t=2349s”