At present, most front-end interviews will ask questions about the event loop, execution stack and so on. This article will explain these concepts to you through cases, pictures and other forms. If you read them carefully, I believe most people can thoroughly understand them

JS memory mechanism

Javascript has an automatic garbage collection mechanism that periodically checks unused variables for collection and release. Therefore, in closures, if external variables are referenced, they cannot be released and collected and are generally 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 basic data types

Number String Null Undefined Boolean Symbol
Copy the code

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 of reference data types are objects stored in heap memory. Javascript does not allow direct access to locations in memory, so we cannot directly manipulate the heap memory space of objects

var num = 1; // n var name = 'come on baby'; Var user = {name: 'bobo'} var user = {name: 'bobo'} Var arr = [1, 3, 5]; 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

var a = 20; var b = a; b = 30; // a is 20, b is 30, the value type does not affect console.log(a); var user = {name: 'bobo'} var info = user; Info. Name = 'Jack' // Print 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

Execution stack

JS code will create an execution context, also can be interpreted as an execution context, JS has three types of execution context:

  • 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 are executed? Execute from top to next? Stack is a kind of data structure, following the principle of “first in, last out”. The execution stack in JS has such a structure. When the engine encounters JS code, it will generate a global execution context and push it into the execution stack. The engine executes the function at the top of the stack. When the execution is complete, the current execution context pops up.

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

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
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

[Printed results of the above interview questions: 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.

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, print 1, and exit the stack

  3. Push the synchronization code New Promise onto the stack to execute, print 3, and exit 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, print 2, and exit the stack
  2. The microtask is executed first, so all the events in the microtask queue are taken out and put into the execution stack for execution. Print 100 and unstack
  3. Fetch only one event from the macro task queue and put it on the execution stack, printing 4

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