The setTimeout and setInterval of JavaScript are two methods that can easily fool others' feelings, because we often start to think that the call will be executed in the established way. I think many people share the same feeling. For example
The Code is as follows:
SetTimeout (function () {alert ('Hello! ');}, 0 );
SetInterval (callbackfunctions, 100 );
It is assumed that the greeting method in setTimeout will be executed immediately, because it is not just a thin air, but the JavaScript API documentation clearly defines the second parameter meaning how many milliseconds later, the callback method is executed. it is set to 0 ms, and it is a matter of course immediately executed.
Similarly, I believe that the setInterval callbackFunction method is executed immediately at an interval of 100 milliseconds!
However, as JavaScript Application Development experiences continue to increase and enrich, one day you may find a piece of weird code that cannot be understood:
The Code is as follows:
P. onclick = function (){
SetTimeout (function () {document. getElementById ('inputfield'). focus () ;}, 0 );
};
Since it was executed after 0 milliseconds, what are setTimeout? At this moment, the firm belief has begun to shake.
Until the last day, you accidentally wrote a piece of bad code:
The Code is as follows:
SetTimeout (function () {while (true) {}}, 100 );
SetTimeout (function () {alert ('Hello! ');}, 200 );
SetInterval (callbackfunctions, 200 );
The first line of code is in an endless loop, but soon you will find that the second and third lines are not unexpected. alert greetings are not displayed, and callbacKFunction has no news!
At this moment, you are completely confused. This kind of situation is unacceptable, because it is painful to change the long-established cognitive process to accept new ideas, but the fact is at present, the Exploration of JavaScript truth will not stop because of the pain. Let's start exploring JavaScript threads and timers next!
Open the cloud and see the moon
One of the main reasons for all the mistakes above is that the subconscious thinks that the JavaScript engine has multiple threads to execute and the JavaScript timer callback function is executed asynchronously.
In fact, JavaScript uses the blind eye method, and most of the time it deceives our eyes. Here, the backlights need to clarify the fact:
The JavaScript engine runs in a single thread. At any time, the browser only has one thread running JavaScript programs.
It is also meaningful for the JavaScript engine to run with a single thread. A single thread does not need to care about the complicated issues of thread synchronization, which simplifies the problem.
So how does the single-threaded JavaScript Engine work with the browser kernel to process these timers and respond to browser events?
The following is a brief description of the browser kernel processing method.
The browser kernel implementation allows multiple threads to run asynchronously. These threads work with each other under kernel control to maintain synchronization. if a browser kernel has at least three resident threads: javascript Engine threads, interface rendering threads, and browser event triggering threads, there are also some threads that terminate upon execution, such as the Http request thread, which will generate different asynchronous events, the following figure illustrates how the JavaScript engine of a single thread interacts with other threads. although the implementation details of each browser kernel are different, the calling principle is similar.
As shown in the figure, the JavaScript engine in the browser is event-driven. Events here can be seen as various tasks sent to it by the browser. These tasks can be derived from the code block currently executed by the JavaScript engine, for example, if you call setTimeout to add a task, you can also use other threads in the browser kernel, such as interface elements, mouse-click events, scheduled trigger time arrival notifications, and asynchronous request status change notifications. from the code point of view, the task entity is a variety of callback functions, and the JavaScript engine has been waiting for the arrival of tasks in the task queue. due to the single-threaded relationship, these tasks must be queued and processed by the engine one after another.
T1-t2 .. tn indicates different time points, and the corresponding small blocks under tn represent the tasks at this time point. For example, if the time is t1, the engine runs in the task block code corresponding to t1, at this time point, we will describe the status of other threads in the browser kernel.
T1 time:
GUI rendering thread:
This thread is responsible for rendering HTML elements in the browser interface. When the interface needs to be repainted or a certain operation triggers a reflow, this thread will execute. although this article focuses on the JavaScript timing mechanism, it is necessary to talk about the rendering thread, because the thread and the JavaScript engine thread are mutually exclusive, which is easy to understand, because the JavaScript script can manipulate DOM elements, when modifying these element attributes while rendering the interface, the element data obtained before and after the rendering thread may be inconsistent.
When the JavaScript engine runs the script, the browser rendering thread is suspended, that is, it is "Frozen.
Therefore, an update operation on the interface, such as adding a node, deleting a node, or changing the appearance of a node, is not immediately displayed. These operations are saved in a queue, the JavaScript engine has the opportunity to render it when it is idle.
GUI event trigger thread:
The execution of JavaScript scripts does not affect the trigger of html element events. During the t1 period, the user clicks a mouse key and the mouse click event is captured by the browser event trigger thread, as shown in the figure, for the JavaScript engine thread, this event is asynchronously uploaded to the end of the task queue by other threads. Because the engine is processing the task at t1, the mouse click event is waiting for processing.
Scheduled trigger thread:
Note that the browser model timing counters here are not counted by the JavaScript engine, because the JavaScript engine is single-threaded and cannot be counted if it is in the congested thread state, it depends on the external timing and triggers timing, so the scheduled events in the queue are also asynchronous events.
As shown in the figure, after the mouse click event is triggered during this t1 period, the previously set setTimeout time has also arrived. For the JavaScript engine, the scheduled trigger thread generates an asynchronous scheduled event and stores it in the task queue. The event is scheduled to wait for processing after the Click Event Callback.
Similarly, in the t1 period, a setInterval timer is also added. Due to the interval, the timer is triggered twice consecutively in the t1 segment, these two events are arranged at the end of the Team for processing.
It can be seen that if the time period t1 is very long and far greater than the scheduled interval of setInterval, the scheduled thread will continuously generate asynchronous scheduled events and put them at the end of the task queue regardless of whether they have been processed, however, once task t1 and the first scheduled event have been processed, the scheduled events in these arrays are executed continuously, because for the JavaScript engine, the Processing Methods of each task in the queue are the same, but the processing order is different.
After t1, that is to say, the current processed task has been returned. the JavaScript engine checks the task queue and finds that the current queue is not empty. The corresponding task execution under t2 is taken out, and other times are pushed accordingly, from this point of view:
If the queue is not empty, the engine extracts a task from the queue header until the task is processed, that is, the engine returns and runs the next task, other tasks in the queue cannot be executed before the task is returned.
I believe that you have understood whether JavaScript can be multithreading and understand the JavaScript timer running mechanism. Let's analyze some cases:
Case 1: setTimeout and setInterval
The Code is as follows:
SetTimeout (function (){
/* Code block ...*/
SetTimeout (arguments. callee, 10 );
}, 10 );
SetInterval (function (){
/* Code block ...*/
}, 10 );
The two pieces of code have the same effect. In fact, they are not the same. In the first section, the setTimeout In the callback function is executed by the JavaScript engine before setting a new setTimeout timer, assume that the previous callback is processed at a time interval from the end of the next Callback. The theoretical interval between the two setTimeout callback executions is greater than or equal to 10 ms. in the second paragraph, after the setInterval is set to a scheduled time, the scheduled thread will continuously generate asynchronous scheduled events every 10 seconds and put them at the end of the task queue. In theory, the two setInterval callback execution intervals are <= 10.
Case 2: Is ajax asynchronous requests actually asynchronous?
Many of my friends are confused. Since JavaScript runs in a single thread, is XMLHttpRequest truly asynchronous after connection?
In fact, the request is indeed asynchronous, but this request is a new thread request from the browser (see). When the Request status changes, if the callback has been set previously, this asynchronous thread generates a state change event, which is placed in the processing queue of the JavaScript engine to be processed. When a task is processed, the JavaScript engine always runs a callback function in a single thread, the specific point is to run the function set by onreadystatechange in a single thread.