A preface.

Javascript, which is the core of the front-end developer, the developer is very necessary to understand how to parse the browser is JS code, if you don’t understand, in the development often because they do not understand the principle and cause of some wrong understanding to stay on the surface, but not from nature to know the reason why it appears, in the solution is not so smooth.

The resources

Operating Systems (3rd Edition) by Luo Yu et al

Does JS have to be at the bottom of the Body? Let’s talk about browser rendering

Front-end must know must know JS single thread and asynchronous

Let’s talk about JavaScript event loops in a nutshell

From browser multi process to JS single thread, JS running mechanism is the most comprehensive combing

Processes and threads

Why does the operating system introduce the concept of processes and threads and what kind of problems they solve

Process of 1.

In the operating system, the program uses system resources in the way of process, including the space used by the program and data, system peripherals, files and other system resources required by the program to run, and uses processor resources in the way of time-sharing. During the running of a process, the operating system continuously allocates system resources to the process in an exclusive way or by sharing with other processes.

Thread 2.

A thread is a smaller unit of a process that can contain multiple concurrent threads of execution within a process. The system will allocate all system resources other than CPU (such as main memory, peripherals, files, etc.) according to the process, and the program depends on the thread to run, the system allocates CPU resources according to the thread, after introducing the thread, the concept connotation of the process has changed, the process only does the allocation unit of system resources other than CPU.

3. The relationship between processes and threads

A process must contain at least one thread, and the introduction of threads allows the process to be refined into parts that can be executed concurrently.

For example, a program that implements weather forecasting can process weather data for Beijing, Shanghai, and Guangzhou in parallel. If the traditional process is used to implement the execution of the weather forecast program, it is impossible to implement the parallel execution of data processing in different areas because of the sequential execution of the in-process program.

Three. Synchronous and asynchronous

1. The synchronous

Synchronization is doing one thing in order to do the next. This is often understood as a program, or a block of code, a function, etc. So what’s done? From a programming point of view, it can be understood that a program is finished when all its code is executed or when a result is returned.

2. The asynchronous

The short answer is: two things going on at once. From a programming perspective, it can be understood as two programs running at the same time. Since both programs are running at the same time, it is inevitable that:

  • The end of each (the end of each may be the same or different)
  • The result of each end

4. Browser processes

The first thing you need to know is that the browser is multi-process, and when you run the browser, the system allocates some system resources to it

1. What processes are included in the browser

  • The Browser process is the main process of the Browser. It is responsible for creating and destroying other processes, downloading and managing network resources, displaying Browser interfaces, moving forward and backward, and so on.

  • GPU process: used for 3D drawing, a maximum of one.

  • Third-party plug-in process: Each type of plug-in corresponds to one process, which is created only when the plug-in is used.

  • Browser rendering process (browser kernel) : internal is multi-threaded, each new page opened will create a process, mainly used for page rendering, script execution, event processing, etc.

2. How is the number of browser processes calculated

  • Whether one or more new blank Windows are opened, only one Browser process is counted as opened
  • Load a web page in a new blank window and count as a browser renderer
  • Other processes count plus one if they are useful

V. Browser rendering process

First of all, let’s understand one thing. What is the main work of the browser in front-end development, and how does it work?

Browser in the front-end development is based on the BS model of the system’s interface display.

The implementation of an interface at the code level mainly includes HTML, CCS and JavaScript. Therefore, in order to display the interface in the browser, the browser must provide the corresponding mechanism to parse, run these three parts of the code, and finally convert the interface into a visual view for the user.

Let’s take a look at how browsers make this transition.

1. Browser rendering process

After the browser requests the page file, it executes the code in the file in sequence, doing the following as it executes

  • Build the DOM

    Parsing HTML into a tree data structure, referred to as DOM, in this process if there are links js, CSS, images and other resources will be launched in parallel requests. DOM tree construction is a deep traversal process. The next sibling node of the current node will be built only after all the child nodes of the current node are built.

  • Build CSSOM

    Browsers parse CSS code into a tree of data structures. Match the style of each element based on the DOM.

  • Build the Render Tree

    After combining DOM and CSSOM, Render Tree is generated. Like DOM, Render Tree saves CSS attributes of each node, attributes of the node itself and child nodes of the node in the form of a multi-fork Tree.

  • Layout

    With Render Tree, the browser already knows what nodes are in the web page, the CSS definition of each node and their dependencies. The next step is Layout, which just as the name implies, calculates the position of each node in the screen.

  • Painting

    After Layout, the browser already knows which nodes to view, what CSS properties each node has, and where each node is on the screen. This is where the final step comes in: Painting, using the graphics card to draw the content to the screen according to the calculated rules.

Note:

Any of the above “build DOM, build CSSOM, build Render Tree” changes may result in repeated “Layout” and “Painting”, which can be summarized in two aspects:

  • Reflow

    Changes to the geometry of the page layout can cause backflow

  • Repaint

    Changes that do not affect the layout of the page but only involve changes in the appearance of the page will cause redrawing

Well, all of this is done by an important process that the browser has handed over to the renderer process. In order to be able to parse and run the various code in the page file, the rendering process is divided into multiple threads, which work together to achieve the display of the page.

Therefore, it is important to know that the browser renderer process is multi-threaded internally.

2. Which threads are included in the browser renderer process

  • GUI rendering engine thread: responsible for rendering browser interface, parsing HTML, CSS, building DOM, CSSOM, Render Tree, Layout, Painting, etc. This thread also executes when the interface needs to be repainted or when Reflow is caused by some operation.
  • JavaScript engine threads: Also known as JavaScript kernels, are responsible for processing, parsing, and running JavaScript code (such as the V8 engine).
  • Event trigger thread: Used to control the browser event loop. Note that this is a browser operation, not a JavaScript engine thread. When an event is triggered, the thread adds the event to the end of the queue, waiting for the JavaScript engine to process it.
  • Timing trigger thread:setIntervalsetTimeoutExecution returns the system ID of the timer trigger, which can be used to cancel the timer trigger. W3C specifies requirements in the HTML standardsetTimeoutIf the interval is less than 4ms, it is 4ms.
  • Asynchronous HTTP request thread: inXMLHttpRequestAfter the connection, a new request thread is opened through the browser, and the state change is detected. If the corresponding state has a callback function, the asynchronous thread will generate the state change event, and put the callback into the event processing queue, waiting for the JavaScript engine to process.

3.GUI rendering threads and JavaScript engine threads are mutually exclusive

The GUI thread is suspended (frozen) while the JavaScript engine thread executes, and GUI updates are kept in a queue until the JavaScript engine is idle. So if the JavaScript takes too long to execute, it will render the page incoherently and cause the page rendering load to block.

JavaScript is single-threaded

1. What about single threads?

The single thread here means that this language is single threaded, which can be understood as the sequence of code execution in the process of program execution is executed in turn. The next line of code must be executed after the last line of code is finished.

2. Why is JavaScript single threaded?

JavaScript can manipulate DOM nodes, and if JavaScript is multithreaded, which means it can be executed concurrently, if JavaScript has two threads at the same time, one thread adds content to a DOM node, and the other thread removes that node, Which thread should the browser take for granted? So to avoid these situations, JavaScript is single-threaded.

3. What are the problems with JavaScript being single threaded

/ / print the I
for (var i = 1; i <= 100; i++) {
	//
}
console.log(i);
Copy the code

In the example above, console.log(I); This statement must be executed after the end of the for loop.

If one statement runs for so long (such as an infinite loop) that the entire page gets stuck in this place, subsequent statements will not execute and the browser will become unresponsive (suspended animation).

In addition, sequential execution will affect the execution time of the program if a block of code takes too long.

7. Task queue

Now that the process and thread issues have been clarified, how does this example work

/ / print 1 to 10
for (var i = 1; i <= 10; i++) {
	setTimeout(function () {
		console.log(i);
	}, 1000);
}
// Result prints 10 11s
Copy the code

This is a piece of JavaScript code that the browser renderer hands off to the JavaScript engine thread. Since JS is a single thread, the code executes in order:

When setTimeout () is executed, the browser renderer starts a new timer thread to execute the callback function inside the timer.

Note that this is a browser operation and does not contradict the fact that JS is single threaded.

In this case, the timer thread will run in parallel with the for loop thread, which is called asynchronous operation.

The callback function inside the timer is JS code, so it’s still handled by the JavaScript engine thread.

There is nothing wrong with the two threads being asynchronous, but where does the result of “printing 10 11s” come from?

To solve this problem? We need to dig a little deeper. What happens to the above code during execution?

First, we need to understand the following:

  • JS is divided into synchronous tasks and asynchronous tasks
  • Synchronization tasks are executed on the main thread, forming an execution stack
  • Outside of the main thread, the event-triggering thread manages a task queue and places an event in the task queue whenever an asynchronous task (such as timer, HTTP request) occurs
  • Once all synchronous tasks in the execution stack are completed (the JS engine is idle at this time), the system reads the task queue, adds runnable asynchronous tasks to the executable stack, and starts execution

According to the specification, event loops are coordinated through the mechanism of task queues. An Event Loop can have one or more task queues. A task queue is a collection of ordered tasks. Each task has a task source. Tasks from the same task source must be added to the same task queue. Tasks from different sources are added to different queues. The setTimeout/Promise API is the source of the task, and the task queue is the specific execution task they specify (the callback function in the API).

8. Macrotasks

It is understood that each task performed by the execution stack is a macro task, which also involves fetching an event callback from the task queue and putting it into the execution stack at a time.

The browser rerenders the page after each macro task and before the next macro task.

Mainly includes:

Script, setTimeout, setInterval, I/O, UI interaction events, postMessage, MessageChannel, setImmediate(Node.js environment)

9. Microtasks

It can be interpreted as a task to be executed immediately after the execution of the current task. That is, the microtask is executed after the current task, before the next task, and before rendering.

After a macroTask has been executed, all microTasks created during its execution have been executed (before rendering).

Mainly includes:

Promise.then, MutaionObserver, process.nexttick (node.js environment)

10. Eventloop

1. What is an event loop

The main thread continuously fetches messages from the message queue and executes them. This process is called an event loop. This mechanism is called a loop.

2. Operation mechanism of event cycle

In an event loop, each operation is called tick. The execution process of each TICK is as follows:

  • Executes a macro task and retrieves it from the task queue if it is not in the execution stack
  • If a microtask is generated during execution, it is added to the microtask queue
  • After the macro task is executed, all the microtasks in the microtask queue are executed in sequence
  • After the current macro task completes, the render is checked, and the GUI thread takes over
  • After rendering, the JS thread takes over and starts the next macro task (fetched from the event queue)

Okay, now that I’m here, that should explain where this example came from, right

/ / print 1 to 10
for (var i = 1; i <= 10; i++) {
	setTimeout(function () {
		console.log(i);
	}, 1000);
}
// Result prints 10 11s
Copy the code

1. The for loop is a synchronous task that is executed on the main thread, forming a stack with I traversed from 1 to 10

2. I will encounter setTimeout in the sequence of traversal from 1 to 10, then the browser rendering process will start a new timer trigger thread, at this time, the thread where the for loop resides and the thread where the timer resides will execute concurrently

3. The setTimeout callback function is an asynchronous operation. The event loop thread will add it to the task queue whose task source is setTimeout, and it will not execute

When I =11 in the for loop, exit the for loop, and the synchronization task ends. At this point, there are no other synchronization tasks in the execution stack of the main thread, so it starts to read tasks (callback function) from the task queue whose task source is setTimeout and adds them to the execution stack of the main thread. Therefore, 10 11s are printed

Execution of Promise, Async /await, and setTimeout in event loop

1. How to execute the tasks in Promise/then and catch

First of all, understand what kind of problem Promise was created to solve? See async/await synchronous execution of asynchronous operations for details on this.

The asynchrony in promises is embodied in then and catch, where the code must wait for the code in the Promise to execute, rather than execute concurrently

Thus, the code written in the Promise is executed as a synchronization task, as soon as it is on the main thread’s execution stack

The codes in THEN and catch will be added to the microtask queue, and will be added to the execution stack until all synchronization tasks are executed.

Note that the code in then and catch is added to the microtask queue, not the task queue. Do not be affected by the statement that “outside the main thread, the event triggering thread manages a task queue, and whenever an asynchronous task (such as timer, HTTP request) occurs, an event will be placed in the task queue.” The asynchronous task in question refers to the asynchronous task being executed by a new thread opened by the browser renderer.

2. How to execute tasks in async/await

Async /await serves the same purpose as Promise and async/await itself is the syntactic sugar of Promise + Generator.

Async code is executed as a synchronous task in the main thread execution stack, as soon as it is its turn to execute.

“Await” is actually a signal to give up the thread. The expression after “await” is executed once, the code after “await” is added to the microtask queue, and then the whole async function is jumped to execute the following code.

3. How to execute tasks in setTimeout

When the JS engine thread meets setTimeout when parsing THE JS code, the browser rendering process will open a new thread timer to trigger the thread. At this time, the callback function in setTimeout will be added to the task queue, and wait for the completion of the last macro task in the main thread execution stack. The callback function is added from the task queue to the execution stack at the next event loop

4. Analyze examples

// Write the output
async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
	console.log('async2');
}

console.log('script start');

setTimeout(function() {
    console.log('setTimeout');
}, 0)

async1();

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');


/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/
Copy the code
  • Above is a piece of JS code. The JS engine thread starts parsing. At this point, there is only one script task in the macro task queue

  • Then we see that two async functions are defined, and then we move on to the console statement, which directly prints script start. After output, script tasks continue to execute, and setTimeout, as a macro task source, will first distribute its tasks to the corresponding queue

  • The script task continues and executes the async1() function. As described earlier, the code in async before await is executed immediately, so async1 start is immediately printed.

    When await is encountered, the expression after await is executed once, so async2 is then output, console.log(‘async1 end’) is added to the Promise queue in microTask, The async1 function is then jumped out to execute the following code.

  • The script task continues and encounters a Promise instance. Since the function in a Promise executes immediately, subsequent.then packets are distributed to the MicroTask Promise queue. Therefore, promise1 is printed and resolve is executed to allocate promisE2 to the corresponding queue.

  • The script task continues until script end is printed, and the global task is complete.

    According to the above, after each macro task is executed, the presence of Microtasks is checked; If so, execute Microtasks until the Microtask Queue is cleared.

  • After the script task completes, the search starts to clear the microtask queue. In this case, the Promise queue has two tasks async1 end and promise2, so asynC1 end, promise2 is output in sequence. The first round of the loop is complete when all Microtasks have been executed.

  • The second cycle starts again with the macro task queue. At this point, there is only one setTimeout in the macro task. You can take it out and output it directly. At this point, the whole process ends.