Register to get access to free programming courses with interactive exercises

Call Stack JS: Asynchronous programming

Before we dive into asynchronous programming, let's take a look at one important 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 is executed only when the previous line is executed. In programming, this sequential execution of code (instructions) 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 the map() method is called, which internally calls Math.sqrt(). In real-world applications, the depth of nesting with functions can be simply 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, and that keeps happening until we reach the deepest possible function. Then, when it comes to returning, the stack comes undone; functions are retrieved from it one by one (in reverse order) and continue their execution from the place where the internal function returned the result.

Suppose 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 process will look like this:

one
=> two
   => three
      => four
   => three
=> two
one

I.e., first it dives down to the nested call, then it climbs up to the first function in the call stack.

We, as developers, see call stacks every day in the error output. Backtrace is nothing more than a call stack written in reverse order. To demonstrate this, I made 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

Running (the code is in the index.js) and output:

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 only grows when calls go further down. This can be seen from the output: the backtrace doesn't include the first and second lines, it describes the sequence starting from the filter call and goes on.

The exception mechanism in js, as in other languages, relies entirely on the presence of a call stack. What's more, it's designed to make it easy to undo this stack. Any exception that arises goes 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);
}

Even though the declaration of the predicate() function containing the error is outside the try/catch block, it will still catch the error inside that function, since predicate() is called internally in the chain.

node index.js

Catch it
ReferenceError: unknown is not defined
    at predicate (index.js:3:32)
    at Array.filter (<anonymous>)

There are special tools that allow you to visualize the call stack. Usually, they're used during profiling⁣ — the process of finding bottlenecks to speed up an application.

Call-stack-analyze

But everything changes when it comes to asynchronous code. More in the next lesson.


Recommended materials

  1. Stack
  2. Call Stack

Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

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.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs

From a novice to a developer. Get a job or your money back!

Frontend Developer icon
Profession
beginner
Development of front-end components for web applications
start anytime 10 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.