05-event loop

event loop

The following knowledge points are all related to the event loop

timer, promise, ajax, node

Understanding this knowledge point is a watershed for the front end, which can improve efficiency, and the strange things in js can be solved. The whole process is based on W3C and Google source code

The browser's process model

What is a process?

A program needs its own dedicated memory space to run, which can be simply understood as a process

 Each application has at least one process, and the processes are independent of each other. Even if they want to communicate, both parties need to agree.

 The benefit of process design is to isolate

What is a thread?

With the process, you can run the code of the program.

The 'person' who runs the code is called a 'thread'.

A process must have at least one thread, so after the process is started, a thread is automatically created to run the code, which is called the main thread.

If the program needs to execute multiple blocks of code at the same time, the main thread will start more threads to execute the code, so a process can contain multiple threads.

What processes and threads does the browser have?

The browser is a multi-process multi-threaded application

The inner workings of the browser are extremely complex, approaching the level of complexity of the operating system

In order to avoid mutual influence and reduce the chance of serial crashes, when the browser is started, it will automatically start multiple processes

 

 Currently one tab and one process

How does the rendering thread work?

The main rendering thread is the busiest thread in the browser, and the tasks it needs to handle include but are not limited to:

  • parsing HTML
  • parsing CSS
  • calculation style
  • layout
  • work with layers
  • Screenshots 60 times per second
  • Execute global JS code
  • Execute the event handler
  • Execute timer callback function
  • ......

Thinking: Why doesn't the rendering process use multiple threads to handle these things? (Work for 2-3 years and think again)

To handle so many tasks, the main thread has encountered an unprecedented problem: how to schedule tasks?

for example:

  • I am executing a JS function, and the user clicks the button halfway through the execution. Should I immediately execute the click event processing function? No, it will add the click event to the task queue
  • I am executing a JS function, and a timer reaches an event in the middle of the execution. Should I immediately execute its callback?
  • The browser process notifies me that "the user clicked the button", at the same time, a certain timer has also expired, which one should I handle?
  • ......

The rendering main thread came up with a neat trick to handle this: queuing

 1. At the beginning, the rendering main thread will enter an infinite loop

while(true) {
    
}

2. Each cycle will check whether there are tasks in the message queue. If there is, take out the first task to execute, and enter the next cycle after executing one; if not, enter the dormant state.

3. All other processes (including processes of other processes) can add tasks to the message queue at any time. New tasks are added to the end of the message queue. When adding a new task, if the main thread is dormant, it will be woken up to continue fetching tasks in a loop.

In this way, each task can be carried out in an orderly and continuous manner.

The whole process is called event loop (message loop)

some explanations

code first

setTimeout(function () {
	console.log(1);
}, 3000)
console.log(2);

If it is synchronous, it will wait for 3 seconds, output 1 first, and then output 2 - blocking the rendering main thread

If it is asynchronous, output 2 immediately, wait for 3 seconds to output 1 ——  

What is asynchronous?

 During the execution of the code, some tasks that cannot be processed immediately, such as:

  • Tasks that need to be executed after the timing is completed - setTimeout, setInterval
  • Tasks to be performed after network communication is completed - XHR, Fetch
  • Tasks that need to be performed after user operations - addEventListener

If the rendering main thread waits for these tasks to arrive, it will cause the main thread to be in a "blocked" state for a long time, causing the browser to "stuck"

 The following is the synchronization process:

The rendering main thread undertakes extremely important work, and it cannot be blocked in any case!

Therefore, browsers choose asynchronous to solve this problem

The following is the asynchronous process:

Using the asynchronous method, the rendering main thread will never block

Interview questions, how to understand the asynchrony of JS?

200-point answer:

JS is a single-threaded language because it runs on the browser's main rendering thread , and there is only one rendering main thread .

The rendering main thread undertakes many tasks, rendering pages and executing JS are all running in it.

If you use a synchronous method, it is very likely that the main thread will be blocked, which will cause many other tasks in the message queue to be unable to be executed.

In this way, on the one hand, the busy main thread will waste time in vain , and on the other hand, the page cannot be updated in time , causing the user to be stuck.

So the browser uses an asynchronous way to avoid it. The specific method is that when certain tasks occur, such as timers, networks, and event monitoring, the main thread will hand over the tasks to other threads for processing, and immediately end the execution of the tasks by itself, and then execute subsequent codes. When other threads are finished, wrap the callback function passed in advance into a task , add it to the end of the message queue, and wait for the main thread to schedule execution.

In this asynchronous mode, the browser never blocks, thus ensuring the smooth operation of the single thread to the greatest extent.

Why does JS block rendering?

Look at the code first

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<h1>hello is loop</h1>
	<button>change</button>
	<script>
		let h1 = document.querySelector('h1')
		let btn = document.querySelector('button')
		/* 死循环指定时间 */
		function delay(duration) {
			let start = Date.now();
			while (Date.now() - start < duration) {}
		}
		btn.onclick = function() {
			h1.textContent = '我变了!';
			delay(3000);
		}
	</script>
</body>
</html>

What happens when the button is clicked?

Stuck, after 3 seconds into text

 What happened in between?

The execution sequence is as follows: onclick click event → change h1 text content → execute delay function → draw

In the second step, the text content has been changed long ago, but it has not been drawn yet, so the page change will be seen after a 3-second delay

If during this process, no matter what other things you do, you have to queue up, that is to say, you have to wait for 3 seconds

So don't let JS run for too long, otherwise the page will freeze

So JS hinders rendering because both JS and rendering are on the browser's rendering main thread!

Solve this problem with fiber in react

Are tasks prioritized?

Tasks have no priority , first in first out in the message queue

But the message queue has priority

W3C originally divided it into macro tasks and micro tasks, but now it abandons this statement because it cannot satisfy the current complex task types, such as network tasks, timer tasks, and interactive tasks.

According to the latest explanation from the W3C:

Each task queue has a task type, tasks of the same type must be in one queue , and tasks of different types can belong to different queues. In an event cycle, the browser can fetch tasks from different queues for execution according to the actual situation.

The browser must prepare a microtask queue, and tasks in the microqueue are executed prior to all other tasks

 Delay Queue: Timer 

Interaction queue: user clicks, window resizing, mouse events, keyboard events

Microqueue: promise, MutationObserver

 upper code

Example 1:

Timer delay 0 seconds

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

Execution result: first output 2 and then output 1, why? Synchronous code takes precedence over delayed queues

 

 

Execution process: execute the global JS first, put the timer function in other threads to wait for execution, 0 seconds, so it is directly added to the delay queue, the timer is placed first, the main thread continues to execute, output 2, after the global is over Look again, there is no micro queue, no interactive queue, and it comes to the delay queue, so the timer function is executed and 1 is output.

Example 2:

The timer is delayed by 0 seconds, and a function with an infinite loop of 1 second is added

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta
		name="viewport"
		content="width=device-width, initial-scale=1.0"
	/>
	<title>Document</title>
</head>

<body>
	<script>
		function delay (duration) {
			let start = Date.now()
			while (Date.now() - start < duration) { }
		}

		setTimeout(function () {
			console.log(1)
		}, 0)

		delay(1000);

		console.log(2);

	</script>
</body>

</html>

Execution result: output 2 first and then 1 after 1 second, why?

Execution process: first execute the global JS, add the timer to other threads, 0 seconds, so it is directly added to the delay queue, the main thread executes down, the 1 second dead loop is executed, and then outputs 2, then look at the task queue, micro No queue, no interactive queue, come to the delay queue,

output 1.

 

 

 

 Example 3:

Add a micro-queue promise to see how it will be executed?

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta
		name="viewport"
		content="width=device-width, initial-scale=1.0"
	/>
	<title>Document</title>
</head>

<body>
	<script>
		
		setTimeout(function () {
			console.log(1)
		}, 0)

		Promise.resolve().then(function() {
			console.log(2);
		})

		console.log(3);

	</script>
</body>

</html>

Execution result: directly output 3 2 1 , why?

Execution process: first execute the global JS, put the timer in other threads, delay 0 seconds, so put it directly in the delayed task, the main thread continues to execute, put the promise in the micro queue, continue to execute, output 3, check the task queue , execute the promise first, output 2, there is no interaction queue, come to the delay queue, and finally output 1.

 

 

 

 Example 4:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta
		name="viewport"
		content="width=device-width, initial-scale=1.0"
	/>
	<title>Document</title>
</head>

<body>
	<script>

		setTimeout(function () {
			console.log(1)
		}, 0)

		function delay(duration) {
			let start = Date.now();
			while (Date.now() - start < duration) {}
		}

		delay(3000);

		console.log(2);

	</script>
</body>

</html>

Execution result: After 3 seconds, first output 2 and then output 1.

Example 5:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta
		name="viewport"
		content="width=device-width, initial-scale=1.0"
	/>
	<title>Document</title>
</head>

<body>
	<script>
		function a() {
			console.log(1);
			Promise.resolve().then(function () {
				console.log(2);
			})
		}

		setTimeout(function () {
			console.log(3);
			Promise.resolve().then(a);
		}, 0)

		Promise.resolve().then(function() {
			console.log(4);
		})

		console.log(5);

	</script>
</body>

</html>

Execution result: 5 4 3 1 2

Implementation process:

Main thread: Execute the global JS, skip function a without calling, come to settimeout, put it into the delay queue: settimeout queues, promise joins the microqueue, returns to the main thread and outputs 5, the global end, microqueue: promise outputs 4, and then Execute settimeout, output 3, put the promise in the microqueue, run the settimeout function, output 1, put the promise in the microqueue, and execute the output 2.

 

 

 

 

 

 General interview questions combine promise + event loop + setTimeout to examine

Interview question: Explain the event loop of JS

 The event loop, also known as the message loop, is the way the browser renders the main thread .

In the source code of Chrome, it starts a for loop that will not end. Each loop takes the first task from the message queue for execution, and other threads only need to add the task to the end of the queue at an appropriate time.

In the past, message queues were simply divided into macro queues and micro queues . This statement can no longer satisfy the complex browser environment , and a more flexible and changeable processing method has been replaced.

According to the official W3C explanation, each task has a different type, and tasks of the same type must be in the same queue , and different tasks can belong to different queues. Different task queues have different priorities. In an event loop, the browser decides which queue to take. But the browser must have a micro-queue, and the tasks of the micro-queue must have the highest priority , and must be scheduled and executed first.

Interview question: Can the timer in JS achieve accurate timing? Why? 

no , because

  1. Computer hardware does not have an atomic clock, so accurate timekeeping cannot be achieved;
  2. The timing function of the operating system itself has a small amount of deviation, and because the timer of JS finally calls the function of the operating system (Apple and Android), it also carries these deviations;
  3. According to the W3C standard, when the browser implements the timer, if the nesting level exceeds 5 layers, it will have a minimum time of 4 milliseconds, which will cause a deviation when the timing time is less than 4 milliseconds;
  4. Affected by the event loop , the callback function of the timer can only run when the main thread is idle (the micro-queue and the interactive queue are completed first, and then it is the turn of the delay queue) , which brings a deviation.

 Summarize:

Single thread is the reason for asynchrony

The event loop is an asynchronous implementation

おすすめ

転載: blog.csdn.net/iaz999/article/details/131343079