Web developers, or front-end engineers, as we prefer to be called, can do almost everything these days, from playing the role of interactivity within a browser to making computer games, desktop controls, cross-platform mobile apps, It can even be written on the server side (most popular is Node.js) and database connections — as a scripting language, the implementation is nearly ubiquitous. So it’s important to understand the inner workings of JavaScript so that we can use it better and more efficiently, and that’s what this article is about.

The JavaScript ecosystem is more complex than it has ever been, and will continue to be. The tools available to build a modern Web application are WebPack, Babel, ESLint, Mocha, Karma, Grunt, etc. – which of these should I use and what is each for? . I find this web cartoon to be a vivid illustration of the inner struggle of today’s Web developers.

The first thing every JavaScript developer needs to do before diving into frameworks or libraries is to understand how to implement the basics of all of this at the most fundamental level. Almost all JS developers have heard of the term “V8”, Chrome runtime, but some may not really understand what they mean or what they are used for. In my first year in development, I didn’t know much about these fancy terms because it was more about getting the job done first. That doesn’t satisfy my curiosity about how JavaScript does this. I decided to dig deeper, googled it and found that good blog posts were rare. What exactly is an Event Loop? | JSConf 2014 in Europe. So I decided to summarize what I learned in the video and share it. Since there are many things that need to be explained first, I will divide the article into two parts. This part will introduce the terms used and then string them together in Part 2.

JavaScript is a single-threaded, single-concurrent language, meaning it can only handle one task at a time, or only run one piece of code at a time. It has a separate Call stack that, along with the rest of the heap, queue, and so on, makes up the Javascript concurrency model (implemented in V8). Let’s start with a brief overview of each term:

  1. Call Stack: A Call Stack is a data structure that records function calls. If we call a function to execute, we’re going to push things on the stack. When we return from a function, that function pops out of the top of the stack.

When we run the program, we first look for the main function — that’s where all our other functions are executed. As shown in the GIF above, the run first starts at console.log(bar(6)), so it is pushed onto the stack. The next frame is the function bar and its arguments, and bar calls the function foo, so foo is pushed on the stack.

Foo returns immediately after execution and therefore pops off the top of the stack. A similar bar pops up from the stack, and finally the console pops up and prints out. All of this happens in milliseconds.

I’m sure you’ve seen the red error stack trace that sometimes appears in the browser console, which basically indicates the current state of the call stack, and functions report errors from top to bottom the same way the stack does. (See below)

Sometimes we get into a wireless loop when we call recursive functions, and Chrome limits the Stack size to 16000 frames, which will terminate your process and pop Max Stack Error Reached (see figure below).

  1. Queue: A JS runtime contains a message Queue, which is a list of messages to be processed and related functions to be called. When the stack has sufficient capacity, the message is pulled from the queue and processed, including the call to the correlation function (thus creating the initial stack frame). When the message processing ends, the stack becomes empty again. In short, these messages are queued based on external asynchronous events, such as a mouse click or receiving a response to an HTTP request, because the callback function is already provided. If, say, someone clicks a button and the button does not provide a callback function, no messages are queued.

Event loop

In general, when evaluating the performance of JS code, it is the function in the stack that determines whether it is fast or slow. Console.log () runs fast, while a function that iterates for or while a lot is much slower and keeps the stack occupied or blocked during execution. So that’s the term you hear or see on Webpage Speed Insights: the blocking script.

Web requests can be slow, image requests can be slow, but thankfully, server requests can be done asynchronously with AJAX. Imagine what would happen if these network requests were made through synchronization. . Network requests are sent to some server, usually another computer/machine. Now, the computer can send back the response very slowly. Also, if a button is clicked, or other rendering needs to be performed, nothing can be done when the stack is blocked. In multithreaded languages like Ruby, other requests can be processed. But in a single-threaded language like JS, it’s not realistic to expect other requests to be processed before a function returns a value on the stack. Web pages suck when the browser can’t do anything. This is not ideal if we want the user to experience a smooth UI. So, what can we do about it?

Concurrency in JS – One Thing at a Time, except not Really, Async Callbacks

  1. Executes the request function, passing the anonymous function as a callback in the onReadyStatechange event, to be executed at some point in the future when the response is available.
  2. The console immediately outputs Script Call done! .
  3. At some point in the future, the response arrives and our callback executes, outputs its response body to the console caller and the decoupling of the response allows the JavaScript Runtime to perform other operations while waiting for the asynchronous operation to complete and its callback to fire.

2 This is where the browser’s own apis come in, called to handle asynchronous events such as DOM events, HTTP requests, StimeTimeUT, and so on. (With this in mind, in Angular 2, Zones are used to repackage these apis to cause runtime change detection, and I can now see how they work.)

Now, these Webapis themselves can’t put execution code on the stack, and if they do, that execution code will randomly appear in your code. The message invocation queue discussed above illustrates this process. Any of the 3Web APIS pushes the callback to the queue when it is finished executing. The event loop is now responsible for executing these callbacks in the queue and pushing them onto the stack when it is empty. The basic job of the event loop is to watch the stack and the task queue, and when the stack is empty, push the first item in the queue onto the stack. Each message or callback is processed completely before any other message is processed.

In the next section, I’ll show a visual animation of the code executing the above process to further explain what the different types of asynchronous functions are, such as tasks, microtasks, and who has higher priority in the queue. In addition, similar zero-latency hacks are used to perform certain functions.

I hope you enjoyed it. Your valuable advice is the greatest support for me.

annotation

Understanding Javascript Function Executions — Call Stack, Event Loop, Tasks & More