Nowadays, most front-end interviews will ask questions about the event cycle, execution stack and so on. This article will explain these concepts to you in the form of case lists and pictures. If you read them carefully, I believe 90% of students can understand them thoroughly.

JS memory mechanism

JavaScript has an automatic garbage collection mechanism that periodically checks unused variables for collection and release. So in closures, if external variables are referenced, they cannot be released or reclaimed; they are usually passed in.

Garbage collection: Finds variables that are no longer in use and then frees their memory, which the garbage collector does periodically at regular intervals.

In JS, each data needs a memory space, which is divided into stack memory and heap memory.

Stack memory generally stores the underlying data types

Number String Null Undefined Boolean Symbol
Copy the code

Look at an example:

var num = 1 
Copy the code

We define a variable num, and the system automatically allocates storage space. We can directly manipulate values stored in stack memory space, so the underlying data types are accessed by value.

The storage and use of data in stack memory is similar to the stack data structure in data structure, following the last in, first out principle.

Heap memory typically stores reference data types

var user = { name:'jack' }
var arr = [1.3.5]
Copy the code

JS reference data types, such as Array, have variable values. Values that reference data types are objects held in heap memory. JavaScript does not allow direct access to locations in heap memory, so we cannot directly manipulate the heap memory space of objects.

And you can see that visually by looking at this picture.

var num = 1;   / / stack
var name = 'Front-end future'; / / stack

// The user variable exists in stack, {name:' riverside '} exists in heap memory
var user = { name: 'river' }; 
// The variable arr is stored in stack, and [1, 2, 3] is stored in heap memory as an object
var arr = [1.3.5]; 
Copy the code

So when we access a reference data type in the heap, we actually get the pointer to that object from the stack first, and then we get the data we need from the heap.

Therefore, we often say that primitive assignment does not affect each other, but reference assignment does affect the original object.

Here’s an example:

var a = 20;
var b = a;
b = 30;
// a is 20, b is 30, the value type does not matter
console.log(a) 

var user = { name: 'river' }; 
var info = user;
info.name = 'Jack'
// Prints as jack, pointing to the same memory address
console.log(user.name)
Copy the code

Conclusion:

  • JavaScript has automatic garbage collection
  • JS memory is divided into heap memory and stack memory
  • Reference types hold Pointers in the stack and object values in the heap
  • Stack memory data follows first in last out

EventLoop

EventLoop is one of the most popular topics in front-end interviews, but to be honest, a lot of people are still confused after reading countless articles. Today, they still use code and images to demonstrate the effect.

To better understand the event mechanism, we need to introduce the execution stack. All JS code runs are put into execution, following in and out of the stack until the stack is emptied.

Execution stack

JS code creates an execution context before it runs. There are three types of execution context in JS:

  • The global execution context, by default, is the Window object in the browser
  • Function execution context. JS functions create a context every time they are called.
  • Eval executes the context. The Eval function generates its own context.

Usually, we have more than one context in our code. What is the order in which these contexts should be executed? Do it from the top down?

Stack is a data structure that follows the principle of “first in, last out”. The execution stack in JS has such a structure. When the engine encounters JS code for the first time, it will generate a global execution context and push it into the execution stack. Every time it encounters a function call, it will push a new context into the stack. The engine executes the function at the top of the stack. When the execution is complete, the current execution context pops up.

Next, let’s look at an example:

function foo() {
  console.log('1');
  bar();
  console.log('3');
}
function bar() {
  console.log('2');
}
foo();
Copy the code

There’s no doubt about that, you all know the answer, how does the stack get called?


The JS file is first executed, creating a global context and pushing it onto the stack. When foo() is called, the execution context of foo is pushed onto the stack, and output ‘1’ is executed. When the bar() function is called, push the execution context of the bar function onto the execution stack, and then execute the output ‘2’; When bar() completes, it is ejected from the stack, and foo() takes over, printing ‘3’; The foo() function completes, gets popped off the stack, and finally clears the stack. This is called “first in, last out”, where Foo is pushed onto the stack and then popped off the stack

EC stands for Execute Context

Conclusion:

  • All JS code to run, need to put in the execution stack.
  • There are three types of execution context (global, function, eval)
  • A stack is a data structure that follows first in, last out

Next, a classic interview question

console.log(1)
new Promise(function(resolve){
    console.log(3)
    resolve(100)
}).then(function(data){
    console.log(data)
})
setTimeout(function(){
    console.log(4);
})
console.log(2)
Copy the code

The printed results of the interview questions above: 1 3 2 100 4

Can you tell us how to do it?

We all know that JS is single-threaded and can only do one thing at a time, but how does it handle things like timers and promises? I’m actually going to introduce you to the Quene queue.

The main thread executes synchronous code blocks. When it encounters asynchronous tasks such as timers and promises, it creates an event queue and throws them into the queue. When the main thread completes execution, it goes back to executing tasks in the queue.

Therefore, our JS execution mainly includes synchronous tasks and asynchronous tasks. The whole synchronous task will enter the main thread, and finally put into the execution stack, which is the execution stack we explain to you above. Next, focus on asynchronous tasks.

In browser JS, asynchronous tasks are divided into macro tasks and micro tasks. Macro tasks and micro tasks belong to queues rather than stacks. A queue will be created for microtasks and a queue will be created for macro tasks. After the execution of the main thread, the microtasks will be first executed, and all the microtasks will be put into the execution stack. Finally, one macro task will be put into the execution stack for execution, and another macro task will be taken until all the macro tasks are executed.

Here’s a picture:


The JS diagram on the left contains the heap and stack, and all codes will be put into the stack for execution, which is called the execution stack. The execution stack is a main thread. Synchronous tasks will be executed first, and asynchronous tasks such as Ajax and setTimeout will be pushed to the queue in the middle.

Let’s look at the example above:

console.log(1)
new Promise(function(resolve){
    console.log(3)
    resolve(100)
}).then(function(data){
    console.log(data)
})
setTimeout(function(){
    console.log(4);
})
console.log(2)
Copy the code
  1. Create the global context and push it onto the execution stack
  2. Push the synchronization code console.log onto the stack to execute and print1And out of the stack
  3. The synchronization code New Promise is pushed onto the execution stack to execute and print3And out of the stack

Note that the new Promise process is actually synchronous, only resolve and Reject are asynchronous

  1. Then is an asynchronous task that is pushed into the microtask queue and creates events
  2. SetTimeout is an asynchronous task that pushes into the macro task queue and creates the event

Note: Macro and micro tasks are two queues

  1. Push the synchronization code console.log onto the stack to execute and print2And out of the stack

At this point the entire execution stack is left with the global context and no code to execute

  1. The microtask is executed first, so all the events in the microtask queue are taken out and put into the execution stack for execution. print100And out of the stack
  2. Only one event is fetched from the macro task queue and placed on the execution stack to execute, printing4

Let’s change the above example:

console.log(1)
new Promise(function(resolve){
    console.log(3)
    resolve(100)
}).then(function(data){
    console.log(data)
}).then(function(){
    console.log(200)
})
setTimeout(function(){
    console.log(4);
})
setTimeout(function(){
    console.log(5);
})
console.log(2)
Copy the code

There are 2 “then” and 2 “setTimeout”, how many do you think should be printed after learning? The answer is: 1, 3, 2, 100, 200, 4, 5

This is the end of the whole article, I hope you can understand!

Conclusion:

  • JavaScript has automatic garbage collection
  • JS memory is divided into heap memory and stack memory
  • Reference types hold Pointers in the stack and object values in the heap
  • All JS code to run, need to put in the execution stack.
  • Before executing code, the execution context is created
  • There are three types of execution context (global, function, eval)
  • Synchronous tasks are executed first, and asynchronous tasks are queued
  • Microtasks are executed first, macro tasks later
  • All microtasks are pulled onto the execution stack, and macro tasks are pulled one at a time
  • Stacks are fifo, queues are fifO

How many of you understand the bold text, which is actually illustrated by the images and the code.

The above is for you to sort out the heap, stack, event mechanism and other concepts, I hope you can speak a zhang SAN, Li Si to the interview, do not be diss.

Wechat official account: Front-end future


Personal wechat:


This article is formatted using MDNICE