Google V8 (1): event loop

Time:2021-4-18

preface

Early browser pages were run onUI threadIn order to introduce JavaScript into the page and facilitate JS to operate DOM, JS also needs to run in the same thread as the page, so JS is single threaded.

1、 Basic concepts

The event loop system consists of main thread, call stack, macro task, micro task and message queue.

Main thread: UI thread
Call stack: a data structure used to manage the call relationships of functions executed on the main thread
Message queue: used to store the “event” list of macro tasks waiting for the main thread to execute

Task: each time a UI thread fetches an event from the message queue and executes an event, it is called a task
Macro task: the events waiting to be executed by the main thread in the message queue. Macro tasks include mouse, keyboard and touchpad events
Micro task: a function that needs to be executed asynchronously at the end of the main thread and before the end of the current macro task

Common macro tasks include:Main JS, UI rendering, setTimeout, setinterval, setimmediately, requestanimation frame, I / O, etc

Common micro tasks include: process.nextTick ()、 promise.then () (new promise doesn’t count!) 、 Object.observe () etc

2、 Event cycle

life cycle

=>Initialization

1. Remove task from message queue
2. The global execution context is pushed into the call stack
3. Creating a micro task queue in a global context

=>Carry out the task

During the event execution:
1. Add a new context to the call stack
2. Execute the code in the function
3. Encapsulates new events and adds them to the message queue

After the event:
1. After the function is executed, the execution context of the current function is ejected from the call stack
2. Query and execute micro task queue in global context
3. Garbage collection?

=>Ends the current event

Take new events from the message queue and start to execute and cycle
Graphic explanation

Note: some of the pictures in this article are from geek time: illustrated Google V8. If there is any infringement, please delete them. Thank you!

Use the following code as an example to understand the event loop mechanism:
function foo() {
    console.log('setTimeout star');
    out && out();
    
    console.log('Promise star');
    pro && pro();
    
    console.log('bar star');
    bar && bar();
}

function bar() {
    console.log('bar');
}

function pro() {
    Promise.resolve().then(res => {
        console.log('Promise');
    });
}

function out() {
    setTimeout(function() {
        console.log('setTimeout:');
    }, 100);
}

foo();

Remove from message queuefoo()event
Create the call stack and push the global execution function context into the stack
: push the foo function execution context onto the stack
: Executionconsole.log('setTimeout star');
: willoutThe function execution context is pushed onto the stack
: willCallback function of setTimeoutEncapsulate a new event and add it to the message queue after 100ms
outFunction execution ends and the out function context is ejected from the call stack
: Executionconsole.log('Promise star');
: willproThe function execution context is pushed onto the stack
: willMicro taskThe global execution context added to the call stackMicro task queuein
proFunction execution ends, and the pro function context is ejected from the call stack
: Executionconsole.log('bar star');
: willbarThe function execution context is pushed onto the stack
: Executionconsole.log('bar');
barFunction execution ends and the bar function context is ejected from the call stack
From the global execution function contextMicro task queueGet the function, executeconsole.log('Promise');
End the current event whenSetTimeout eventAfter adding to the message queue, the event is taken out and executedconsole.log('setTimeout');

3、 Common related questions

stack overflow
function foo() {
    foo();
}

foo()

In the above code, we call ourselves in the foo function. According to the event cycling mechanism we understand above, we will find that in executing the foo function, the main thread will press into the execution context of the foo function continuously into the calling stack, and because the foo function is never executed, the function context will not be removed from the call stack, but the capacity of the call stack is limited. So it will overflow the call stack.

Faced with such problems, we have two solutions:
1. Macro task asynchronous call

function foo() {
    setTimeout(function() {
        foo();
    }, 0);
}

//Here is the code directly, according to the above content, we can analyze why it will not cause stack overflow (I will not admit that I am too lazy to write ~)
//In addition, it should be noted that even if this does not cause stack overflow, we still do not recommend writing like this. A large number of events block the execution of other events in the message queue

2. End call by condition — recursive function

Execution order of macro task and micro task

Copy the code of the above case to the browser for execution, and we will find thatfoo();The results of implementation are as follows:

//Print results:
// setTimeout star
// Promise star
// bar star
// bar
// Promise
// setTimeout

Here we notice a problem, that is, although the execution order of the three functions in the code is setTimeout, promise and bar, the final execution result is bar, promise and setTimeout due to the different processing methods of the browserSynchronous and asynchronousMicro task and macro taskAccording to the results of the above code and our analysis of the execution process of this code, we can draw the following conclusions:

  • Synchronous before asynchronous
  • The micro task is executed after the main thread execution event and before the current macro task
  • According to the second article, if there are micro task and macro task in an event, micro task will be executed before macro task.
The execution time interval of timer functions such as setTimeout and setinterval

Let’s think about a problem first. In the above code, the delay of setTimeout should be set to 100ms. Theoretically, the time interval between printing setTimeout star and setTimeout should also be 100ms, but the real situation is like this.

Because the main content of this article is event cycle, here is the answer:Not at all!!!

The reason will be explained in a separate article later, please pay attention!

Recommended Today

Envoy announced alpha version of native support for windows

Author: sunjay Bhatia Since 2016, porting envoy to the windows platform has been an important part of the projectOne of the goalsToday, we are excited to announce the alpha version of envoy’s windows native support. The contributor community has been working hard to bring the rich features of envoy to windows, which is another step […]