Before we dive into asynchronous programming, let's observe one key point related to code execution.
Take a look at this example:
const data = [16, 64, 4];
const data2 = data.map(Math.sqrt); // [4, 8, 2]
const predicate = (v) => v > 2;
const data3 = data2.filter(predicate); // [4, 8]
Each line in the code above runs only when the previous line has already been executed. In programming, this sequential execution of code is called synchronous. And the execution of each particular line can be as complex as you like.
If you look at the second line, you can see that we call the map()
method, which internally calls Math.sqrt()
. In real-world applications, the depth of nesting with functions can be enormous, reaching hundreds of levels.
During code execution, this kind of failure creates a call stack. Why a stack? Because that's how the code execution process works.
Each internal call adds the current function inside the stack. That keeps happening until we reach the deepest function possible. Then, when it comes to returning, the stack comes undone. The functions are retrieved from it one by one in reverse order and continue their execution from the moment where the internal function has returned the result:
Imagine we have a chain of functions one() calls two(), which calls three(), which calls four():
const four = () => console.log('END!');
const three = () => four();
const two = () => three();
const one = () => two();
one(); // Running
Then the code execution will look like this:
one
=> two
=> three
=> four
=> three
=> two
one
So, first, there is a dive to the nested call, then a climb up to the first function in the call stack.
As developers, we see the call stack every day in the error output. A backtrace is nothing more than the call stack written in reverse order. To illustrate, let's make a mistake in the third line of our code:
const data = [16, 64, 4];
const data2 = data.map(Math.sqrt); // [4, 8, 2]
const predicate = (v) => unknown > 2;
const data3 = data2.filter(predicate); // ReferenceError
Let's observe its running and output. The code is in the index.js:
node index.js
index.js:3
const predicate = (v) => unknown > 2;
^
ReferenceError: unknown is not defined
at predicate (index.js:3:32)
at Array.filter (<anonymous>)
at Object.<anonymous> (index.js:4:21)
It is important to understand that the call stack grows only when calls go further in depth. You can see this in the output: the backtrace does not include the first and second lines, it describes the sequence starting from the filter call and beyond.
Like in other languages, the exception mechanism in JavaScript relies entirely on the existence of a call stack. Moreover, an exception mechanism makes it easier to unwind this stack. Any exception that arises moves up the call stack until it encounters a try/catch construct or until the call stack runs out.
const data = [16, 64, 4];
const data2 = data.map(Math.sqrt); // [4, 8, 2]
const predicate = (v) => unknown > 2;
try {
const data3 = data2.filter(predicate); // ReferenceError
} catch (e) {
console.log('Catch it');
console.log(e.stack);
}
The declaration of the predicate()
function contains an error. Even though it is outside the try/catch block, an error will still be caught inside this function since predicate()
is called internally along the chain:
node index.js
Catch it
ReferenceError: unknown is not defined
at predicate (index.js:3:32)
at Array.filter (<anonymous>)
There are some tools for visualizing the call stack. Usually such tools help in profiling, the process of finding bottlenecks to speed up the application.
But everything changes when it comes to asynchronous code. More on this we will discuss later in the course.
Recommended materials
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.