Looks like no one added any tags here yet for you.
What is asynchronous programming?
Asynchronous programming allows executing code separately from the main application code without blocking it.
It is used when the response of an operation is not immediately available.
Asynchronous code is written using asynchronous callbacks or promises.
What is an asynchronous callback?
An asynchronous callback is a function that is passed as an argument to another function that is executed in the background.
It is executed when the background code finishes execution.
What is a promise?
A promise is an object that is returned by asynchronous code and represents the completion or failure of the asynchronous operation.
It is either resolved or rejected.
A .then() block can be used to handle a promise when it is resolved.
A .catch() block can be used to handle a promise when it is rejected.
Multiple .then() blocks can be used when multiple asynchronous operations need to be executed.
What is the Async/Await syntax?
The async/await syntax can be used to make it easier to work with promises.
It requires the use of async and await keywords.
The async keyword is added to the front of a function that should contain asynchronous code.
The await keyword is added to the front of an asynchronous function call that returns a promise.
Things to consider with asynchronous code?
Execution - The application continues to run, and when the asynchronous code finishes, it gets the result. This model can be used to perform multiple actions at the same time.
Fetching resources - Asynchronous code is typically used to fetch resources from the network. For example, it is used when an HTTP GET request is sent to a server to retrieve data.
Approaches - When writing asynchronous code, two approaches are used for performing asynchronous tasks: callbacks and promises.
How are asynchronous callbacks executed?
An asynchronous callback is a function that is provided as an argument when calling another function that executes code in the background.
When the code in the background finishes, the asynchronous callback function is invoked.
// This example uses addEventListener to associate an asynchronous callback with the 'complete' button.
document.querySelector('#complete').addEventListener('click', (event) => {
console.log('Button was clicked!')
}
);
console.log('initial code has finished.');
// Output
initial code has finished
Button was clicked
An example of an asynchronous callback?
// This example shows the use of an asynchronous callback when calling the setTimeout() method.
// setTimeout called with time as zero and passed a function to log a message
setTimeout(function() { console.log('Timer has finished.');}, 0
);
// Displays log below first even though 'setTimeout' is set to 0.
console.log('Code has finished executing.');
Another asynchronous callback example?
// This example shows the use of an asynchronous callback when calling the setInterval() method.
let value = 0;
// The setInterval() method executes a callback function repeatedly after the specified time interval in milliseconds.
// The function actually runs, even though this is just set to a variable
const interval = setInterval(
function() {
value++;
console.log('Value after 2 seconds:', value);
// The clearInterval() method can be used to remove a repeating callback function that has been set using setInterval().
if (value === 5) {
clearInterval(interval);
console.log('Final value:', value);
}
}
, 2000);
// This output is printed first, then the output from the function
console.log('Code after the setInterval method call');
Can you nest asynchronous callbacks?
Yes.
It is possible to nest asynchronous callbacks when multiple asynchronous operations need to be performed consecutively.
However, too many nested callbacks can make the code hard to read.
This is referred to as callback hell.
How do you use a promise?
A promise is an object that represents the completion or failure of an asynchronous task.
If implemented, it is returned by asynchronous code.
Callbacks are attached to a promise to handle the success or failure of the asynchronous task.
Promises, like other asynchronous operations, are put in the message queue, which runs after the processing of the main thread.
A .then() block can be used to handle the success of the asynchronous operation.
A .catch() block can be used for error handling.
How does the fetch() method use a promise?
When the fetch() method is used to fetch a resource, it returns a promise.
A .then() block can be used to execute code when the asynchronous operation is successful.
A .catch() block can be used to handle failure.
// In this example, fetch is used to retrieve a todo.
fetch('https://jsonplaceholder.typicode.com/todos/1')
// Convert response to JSON object
.then(resp => resp.json())
// Display todo
.then(todo => console.log(todo))
// If there's an error, display it.
.catch(err => console.error('Problem fetching data', err));
What is Promise State?
The state of a promise is initially pending.
It then changes to either fulfilled or rejected, depending on whether the asynchronous operation is successful or not.
When a promise is created, resolve(value) or reject(error) is called.
When a promise is created, the 'executor' function is run automatically.
It accepts 'resolve' and 'reject' functions as parameters.
A promise is said to be settled when it's either fulfilled (resolve() is called) or rejected (reject() is called).
See promiseState example code.
What is Promise Chaining?
Two or more asynchronous operations can be executed consecutively, in which case multiple .then() blocks can be used.
This is called promise chaining.
A single .catch() block can be used at the end for error handling.
An example of Promise Chaining?
// This example shows how promise chaining can be used to execute multiple asynchronous operations.
// Initial fetch request to retrieve possible urls returns a promise.
fetch('https://swapi.dev/api/')
// Processing the response with json() returns a promise.
.then(resp => resp.json())
// Using one of the urls to fetch the people returns another promise.
.then(urls => {
return fetch(urls.people);
})
// Processing this response returns a promise.
.then(resp2 => resp2.json())
.then(data => console.log(data))
// Using a .catch() block for error handling.
.catch(error => console.error(error));
What are the Promise static methods?
The Promise object provides access to various useful static methods:
Promise.all
Promise.allSettled
Promise.race
Promise.any
Promise.resolve
Promise.reject
What does the Promise.all method do?
This static method accepts an array of promises and returns a new promise.
It is resolved when all the specified promises are resolved.
What does the Promise.allSettled method do?
This static method accepts an array of promises and returns the status and value/error for each promise.
What does the Promise.race method do?
This static method accepts an array of promises and returns the first settled promise.
What does the Promise.any method do?
This static method accepts an array of promises.
When one of the promises is fulfilled, it returns a single promise.
What does the Promise.resolve method do?
This static method returns a new Promise object that resolves with the specified value.
What does the Promise.reject method do?
This static method returns a new Promise object that is rejected with the specified error.
Example of using a Promise static method?
// These examples will use the following four promises.
const promise1 = new Promise((resolve, reject) => setTimeout(resolve, 1000, 'promise one'));
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 2000, 'promise two'));
const promise3 = new Promise((resolve, reject) => setTimeout(resolve, 1500, 'promise three'));
const promise4 = new Promise((resolve, reject) => setTimeout(reject, 500, 'promise four error'));
// This example shows how to use the Promise.any method for all four promises.
Promise.any([promise1, promise2, promise3, promise4]) .then(valueArray => console.log(valueArray));
// Output after 1 second
promise one
What does the async keyword do?
The async keyword needs to be added in front of a function declaration to turn the function into an async function that can expected asynchronous code.
What does the await keyword do?
The await keyword can be added in front of any asynchronous promise-based function inside an async function.
It can only be used inside async functions.
A synchronous try...catch statement can be used with async/await to add error handling.
The error object is passed to the catch block.
Example of using async and await keywords?
// In this example, the fetch method is used with async/await to retrieve a todo. The try...catch is used to handle any errors.
async function getTodo(id) {
try {
let url = 'https://jsonplaceholder.typicode.com/todos/' + id;
// await the promise to resolve
let resp = await fetch(url);
// await the promise to resolve
let results = await resp.json();
console.log(results);
}
catch(err) {
// catch error if it occurs
console.error('Problem fetching data', err);
}
};
getTodo(5);
JavaScript runtime engine overview?
JavaScript is a single-threaded programming language and is capable of performing only one task at a time.
The runtime engine does not wait for an asynchronous function to complete (i.e. XHR request, DOM Event, setTimeout) and moves on to process the next function in the call stack.
When an asynchronous function completes, and if a callback is provided, the callback method is placed in a message queue.
The job of the event loop is to continuously check the call stack and the message queue. If the event loop sees that the call stack is empty and a message is queued, it pushes the oldest message into the call stack for processing, and waits for the call stack to be empty again before fetching the next message.
Events for a specific object can be monitored by executing the monitorEvents method in the command line of the Console panel. When an event is invoked on the object, the Event object is logged in the console where its properties can be inspected.
What does the Event Loop do?
The event loop continuously checks the call stack and pushes a message from the message queue one at a time for processing as soon as all functions in the call stack are popped out.
The JavaScript runtime engine executes synchronous and asynchronous functions. It uses an event loop to push a message or an asynchronous callback from the message queue for processing after the call stack is emptied.
In what order are functions processed in the call stack?
Functions are processed in the call stack in a "last-in, first-out" order (1 to 8).
Think of a normal call stack, a method calls another method, the called method will be processed first, then the calling method completes.
How is an asynchronous callback method processed?
After an asynchronous function is executed by the browser, its associated callback method is placed in the message queue (A to B).
If there are no functions to process, or when the call stack is empty, the event loop pushes the callback method to the call stack to have it processed (C).
What happens when a function is called?
When a function is called, it is added to the call stack and processed.
The event loop pushes a message from the queue to the call stack when it is empty.
What does the call stack do?
The call stack contains functions that are being processed, in which each function is stacked as a frame. After being processed, the function is popped out the call stack.
What is the heap?
Objects that are created during runtime are allocated in a heap, which is a term used to describe a large region of memory in the running machine.
What is the message queue for?
The message queue, or also known as callback or event queue, is where an asynchronous callback waits to be pushed by the event loop into the call stack for processing.
What is meant by run to completion?
JavaScript operates on a single thread and processes the next message in the queue only after the previous one is completed.
While a function is being processed in the call stack, rendering or user interaction is blocked on the page.
What would happen if an event listener is attached to an event?
When an event occurs and an event listener is attached to it, the associated function is added to the message queue.
A message may only be processed immediately if both the message queue and call stack are empty.
For example, a click event listener is added to a button on a web page.
Each time the button is clicked, the callback method is placed in the message queue.
It then waits for the event loop to push it into the call stack for processing.
How would a setTimeout function be processed?
Calling a setTimeout function with a delay of zero seconds does not guarantee that the callback method will be processed immediately since it will need to wait for its turn in the message queue.
// This example shows how setting a timer of zero second does not necessarily run the function immediately.
console.log('Turn on the faucet.');
setTimeout(() => { console.log('Wash your hands.');}, 0);
console.log('Turn off the faucet.');
// The runtime engine immediately executes synchronous functions in the call stack.
// The callback method is added to the queue first and waits for its turn.
Output:
Turn on the faucet
Turn off the faucet
Wash your hands
What do you need to think about with I/O handling?
Other operations can be performed while waiting for one operation to complete since input and output are handled using events and callbacks.
What considerations are there with using alert and XHR?
It is a good practice to avoid using the alert() function to indicate an exception as well as using a synchronous XMLHttpRequest.
What do you need to be aware of with setTimeout?
Time delay defined in a setTimeout function indicates the minimum time only after which its callback method will be processed. It is not the exact time.
What should you do with long messages?
When a message takes too long to complete, it is a good practice to break the message into shorter messages to avoid blocking the call stack.
How can you monitor the events on a specific object?
Events that occur on an object during runtime can be monitored by calling the monitorEvents method in the Console panel.
This capability allows inspecting the properties of the invoked event.
In the console type:
let mybutton = document.getElementById('mybutton');
monitorEvents('mybutton', 'mouseover');
What are the three ways you can monitor an event?
The monitorEvents method allows three ways of specifying the event or events to monitor for a given object.
EVENT NAME - A single specific name of an event is defined in the command. For example, monitorEvents(element, "click") will log only the click event for the element.
ARRAY OF EVENTS - Events are specified using an array to monitor multiple events. For example, monitorEvents(element,["click", "scroll"]) will log click and scroll events for the element.
EVENT TYPE - Events to monitor are specified using their type. For example, monitorEvents(element, "key") will log the keydown, keyup, keypress, and textInput events.
How can you use the $0, $1, $2 commands with monitorEvents?
The monitorEvents method supports the use of the $0, $1, $2, $3, and $4 commands which act as historical references to the last five DOM elements selected in the Elements panel.
In this example, $0 is used to reference the most recently selected DOM element in the Elements tab and capture all click events on it.
monitor Events($0, 'click');