TIL/2021–01–11
Day 30: Treehouse Full Stack JavaScript Techdegree
Asynchronous Programming with JavaScript:
JavaScript is a synchronous single-threaded language — process and execute only one task at a time
Any time you have code that needs to execute after some period of time in response to an event or upon receiving a data it needs we’re introducing asynchronous behavior into the program
JavaScript and its runtime environment provides efficient ways to handle async operations
Allow other programs to run while other potentially blocking script wait to complete
— —
Understanding asynchronous and synchronous code
Asynchronous
- Getting other work done in the meantime
- Asynchronous is being more efficient (for example: making breakfast requires you to make eggs, make coffee and heat up some toast. For synchronous programming, it would have to be one step at a time — meaning eggs first then coffee then toast which will take up a lot of time. With asynchronous programming it could be in the way of make some coffee and while its brewing some coffee, put the toast in the toaster and then make the eggs while those two tasks are functioning — more efficient)
- More efficient
- A block of code is able to run (even if it is expected to finish later), while letting other code will run at the meantime
- There are methods that make your code run in an asynchronous way
- setTimeout() — lets your code run after a given time
- If your program needs to run tasks that take time we should do our best to make it to run and complete those tasks asynchronously, so other parts in the program can carry on
Synchronous
- Two or more things cannot happen at the same time
- Only one thing is able to run at completion in any given time
- Blocking behavior
- Other programs are blocked from running
- Other functions/tasks are unable to be executed until the current function is done executing
— — -
JavaScript Call Stack
- The JavaScript engine in the browser has a mechanism called call stack — which keeps track of the order of function calls and where it is in a program at any given moment
- Call stack can only process one function call at a time — it is single threaded
- Anytime a function gets called it is pushed into the call stack and any functions inside that function are pushed higher into the call stack when a function is finished executing it gets popped and the next in line gets executed
- When there are no functions left, the call stack is empty
Web APIs
- The call stack handles asynchronous tasks in a different way compared to synchronous tasks
- Whenever the JavaScript environment encounters code that needs to run and execute at a later time, like a setTimeout() callback or a network request, that code is handed off to a special Web API that processes the async operation.Meanwhile, the call stack moves on to other tasks then revisits the async task when it’s ready to be dealt with.
- The asynchronous behavior of JavaScript does not come from the JavaScript engine itself
- Asynchronicity actually comes from the runtime environment. Runtime environments (like web browsers and Node) provide APIs that let JavaScript run tasks asynchronously.
- Where does the async callback go before being pushed onto the call stack? It doesn’t immediately go back into the call stack. Instead the callback gets pushed into something called the callback queue
— — -
The Callback Queue and Event Loop
Callback Queue
- Web APIs are what processed async operations while keeping the call stack clear of blocking operations
- Once a Web API is done processing an async operation it does not immediately go back to the call stack but it is pushed on to the callback queue in a form of a list of async operations waiting to be executed
- You can think of the callback queue as a holding area for all the callbacks that are waiting to be put on the call stack and eventually executed.
- Callbacks for (non-blocking) operations that are scheduled to complete execution at a later time like setTimeout, setInterval, AJAX are added to the callback queue
- Web APIs add each async task to the callback queue where they wait to be pushed onto the call stack and executed one at a time
Event Loop
- Monitors the call stack and callback queue
- Anytime the call stack is empty, the event loop takes the first task from the callback queue and pushes it on to the call stack to execute. After the task executes, it will call the next if there is any — one by one
- The event loop pushes the async task to the call stack one at a time to execute and goes to the next
— -
Implement a Callback:
Higher order function: takes one or more functions as arguments and/or returns the function
This function is now receiving the JSON data passed to it from its parent function, getJSON
This is a callback, it does not get executed right away. Only the first argument gets executed
(json) => {
json.people.forEach(person => {
getJSON(wikiUrl.concat(person.name), generateHTML)
})
So if we log it we go this
And then
We are only calling generateHTML because we will be passing the data it needs once it becomes available after getJSON executes
The reason why we are concatenating the name is because we are adding the first name to the wikUrl api to load his/her profile
Managing nested callbacks
Each callback in our event listener adds a level of nesting and when we have a lot of callbacks the code gets complicated
Callbacks along with the XML http request API can be a bit too complex to use and manage
— —
Why is the order of DOM events passed asynchronously?
To prevent the browser from getting flooded with different events happening all at once
Best description of “the pyramid of doom”: multiple callbacks are nested one after the other, making your code difficult to understand and maintain
A callback function in an asynchronous program executes at some point later, once the parent function received the data it needs