Deep understanding of JavaScript operating mechanism

Deep understanding of JavaScript operating mechanism

Preface

  • This article is written on the occasion of training newcomers to the team, so in fact, the audience of this article is a small partner who does not understand the operating mechanism of JavaScript or has difficulty understanding it . In other words, in fact, the real principles are not completely consistent with what this article describes. Just like middle school textbooks and college textbooks, university teachers will tell you that some things in high school are conclusions obtained under certain ideal circumstances, and this article is the same.
  • The purpose of this article is to hope that everyone can have a more intuitive and faster understanding of the operating mechanism of JavaScript after reading it, but more importantly, do it yourself , only practice can really discover problems and improve :)
  • I have received your support and feedback, thank you very much :)

To understand the operating mechanism of JavaScript, you need to deeply understand the following points:

  • JavaScript's single thread mechanism
  • Task queue (synchronous tasks and asynchronous tasks)
  • Events and callback functions
  • Timer
  • Event Loop

JavaScript's single thread mechanism

One of JavaScript's language features (and the core of the language) is single-threaded . What is single thread? Simply put, only one thing can be done at the same time . When there are multiple tasks, they can only be completed one by one in one order before executing the next one.

The single thread of JavaScript is related to its language usage. As a browser scripting language, the main purpose of JavaScript is to complete user interaction and manipulate the DOM. This determines that it can only be single-threaded, otherwise it will cause complicated synchronization problems.

Imagine that JavaScript has two threads at the same time. One thread needs to add content to a certain DOM node, and the other thread's operation is to delete this node. Then who should the browser take?

So in order to avoid complexity, JavaScript has been single-threaded since its inception.

In order to improve CPU utilization, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the child threads are completely controlled by the main thread and must not manipulate the DOM. So this standard does not change the nature of JavaScript single-threaded.

Task queue

Completing tasks one by one means that the tasks to be completed need to be queued, so why do they need to be queued?

There are usually two reasons for queuing:

  • The task calculation is too large, and the CPU is busy;
  • The things needed for the task are ready and cannot continue to execute, causing the CPU to idle, waiting for input and output devices (I/O devices). > For example, for some tasks, you need Ajax to obtain data before you can proceed

As a result, the designers of JavaScript also realized that at this time, it is possible to run the tasks that are ready later to improve operating efficiency, that is, to suspend the waiting tasks and put them aside, and then execute them after getting the things that are needed. It's like when the other party leaves when answering the call, and there is another incoming call, so you hang up the current call, wait for the end of the call, and then connect back to the previous call.

Therefore, the concepts of synchronization and asynchrony have emerged, and tasks are divided into two types, one is synchronous tasks (Synchronous) and the other is asynchronous tasks (Asynchronous).

  • Synchronous tasks: tasks that need to be executed are queued on the main thread, one after another, and the previous one is completed before the next one is executed
  • Asynchronous task: A task that is not executed immediately but needs to be executed is stored in the "task queue". The "task queue" will notify the main thread when and which asynchronous task can be executed, and then the task will enter the main thread and Be executed. > All synchronous execution can be regarded as asynchronous execution without asynchronous tasks

Specifically, the asynchronous execution is as follows:

  • All synchronization tasks are performed on the main thread to form a execution stack (execution context stack).

    That is, all tasks that can be executed immediately are queued on the main thread and executed one by one.

  • In addition to the main thread, there is also a "task queue". As long as the asynchronous task has a running result, an event is placed in the "task queue".

    That is to say, when each asynchronous task is ready, a unique flag is set, and this flag is used to identify the corresponding asynchronous task.

  • Once all the synchronization tasks in the "execution stack" are executed, the system will read the "task queue" to see what events are in it. Those corresponding asynchronous tasks end waiting for bagging, enter the execution stack and begin to be executed.

    That is, after the main thread finishes the previous tasks, it will look at the flags in the "task queue" to package the corresponding asynchronous tasks for execution.

  • The main thread keeps repeating the above three steps.

    As long as the main thread is empty, it will read the "task queue". This process will be repeated continuously, and this is how JavaScript works.

Events and callback functions

event

The "task queue" is an event queue (can also be understood as a message queue). When an IO device completes a task, it will add a time to the "task queue", indicating that the related asynchronous task can enter the "execution stack" . Then the main thread reads the "task queue" to see what events are in it.

In addition to the events of the IO device, the events in the "task queue" also include some user-generated events (such as mouse clicks, page scrolling, etc.). As long as the callback function is specified, these events will enter the "task queue" and wait for the main thread to read.

Callback

The so-called "callback" (callback) is the code that will be suspended by the main thread. Asynchronous tasks must specify a callback function. When the main thread starts to execute the asynchronous task, the corresponding callback function is executed.

The "task queue" is a first-in, first-out data structure, and the first events are read by the main thread first. The reading process of the main thread is basically automatic. As long as the execution stack is cleared, the first event on the "task queue" will automatically enter the main thread. However, if a "timer" is included, the main thread must first check the execution time, and certain events can only return to the main thread after the specified time.

Event Loop

The main thread reads events from the "task queue", this process is cyclical, so the entire operating mechanism is also called "Event Loop" (event loop)

In order to better understand Event Loop, refer to a picture in Philip Roberts's speech below.

Event Loop

In the above figure, when the main thread is running, heap (heap) and stack (stack) are generated. The code in the stack calls various external APIs and adds various events (click, load, done) to the "task queue" . When the code in the stack is executed, the main thread will read the "task queue" and execute the callback functions corresponding to those events in turn.

The code in the execution stack (synchronous task) is always executed before reading the "task queue" (asynchronous task).

var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function (){};
req.onerror = function (){};
req.send();

The req.send method in the above code is an Ajax operation to send data to the server. It is an asynchronous task, which means that the system will read the "task queue" only after all the code of the current script is executed. Therefore, it is equivalent to the following writing.

var req = new XMLHttpRequest();
req.open('GET', url);
req.send();
req.onload = function (){};
req.onerror = function (){};

In other words, the part of the specified callback function (onload and onerror) is irrelevant before or after the send() method, because they are part of the execution stack, and the system will always read the "task" after executing them. queue".

Timer

In addition to placing events for asynchronous tasks, the "task queue" can also place timed events, that is, specify the time after which certain codes are executed. This is called the timer function, which is the code that is executed regularly.

SetTimeout()And functions that setInterval()can be used to register single or repeated calls after a specified time, their internal operating mechanism is exactly the same, the difference is that the code specified by the former is executed once, and the latter will be called repeatedly at intervals of a specified number of milliseconds:

setInterval(updateClock, 60000); //60秒调用一次updateClock()

Because they are important global functions in client-side JavaScript, they are defined as methods of the Window object.

But as a general function, it doesn't actually do anything to the window.

The setTImeout()methods of the Window object are used to implement a function to run after a specified number of milliseconds. So it accepts two parameters, the first is the callback function, and the second is the number of milliseconds to delay execution. setTimeout()And setInterval()returns a value, which can be passed to clearTimeout()cancel the execution of this function.

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

The execution result of the above code is 1, 3, 2, because the execution of setTimeout()the second line is postponed to 1000 milliseconds.

If setTimeout()the second parameter is set to 0, it means that after the current code is executed (the execution stack is cleared), the specified callback function will be executed immediately (0 millisecond interval).

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

The execution result of the above code is always 2, 1, because the system will execute the callback function in the "task queue" only after the second line is executed.

In short, setTimeout(fn,o)the meaning is to specify a task to be executed in the earliest available free time of the main thread, that is, to execute as early as possible. It adds an event to the end of the "task queue", so it will not be executed until the synchronization task and the existing events of the "task queue" are processed.

setTimeout()The minimum value (shortest interval) of the second parameter specified by the HTML5 standard must not be less than 4 milliseconds. If it is lower than this value, it will automatically increase.

It should be noted that setTimeout()only the event is inserted into the "task queue" , and the main thread will execute its designated callback function only after the current code (execution stack) is executed. If the current code takes a long time, it may have to wait a long time, so there is no way to guarantee that the callback function will be setTimeout()executed at the specified time.

For historical reasons, the first parameter of setTimeout()sum setInterval()can be passed in as a string. If you do this, the string will be evaluated (equivalent to execution eval()) after the specified timeout period or interval .

For an in-depth understanding of the working principle of timers, here is an article by John Resig, the author of jQuery: http://ejohn.org/blog/how-javascript-timers-work/

I also translated this article myself, if you have any questions, please correct me: http://guoxunique.com/2016/12/07/how-javascript-timers-work/

Refer to teacher Ruanyifeng's blog post http://www.ruanyifeng.com/blog/2014/10/event-loop.html

Refer to "JavaScript Definitive Guide"

Guess you like

Origin blog.csdn.net/Amos_liu/article/details/53560434