Recently I was asked by my classmate about JavaScript single-threaded things, I could not answer. Well, I feel like my JavaScript is white. Here are some of the things I've done with JavaScript on a single thread these days.
First, why is JavaScript a single thread?
It's always known that JavaScript runs in a single-threaded fashion. When it comes to threading, you naturally associate it with processes. So what's their connection?
Both processes and threads are concepts of the operating system. A process is an instance of an application that is made up of a private virtual address space, code, data, and other system resources that can request the creation and use of system resources (such as isolated memory areas, etc.) while it is running, and those resources will be destroyed as the process terminates. While the thread is an independent execution unit within the process, the process resources can be shared between different threads, so in the case of multithreading, special attention should be paid to the access control of critical resources. The main thread of the execution process starts after the system creation process, and the life cycle of the process is consistent with the life cycle of the main thread, and the exit of the main thread means that the process is terminated and destroyed. The main thread is created by the system process, and the user can create other threads autonomously, and this series of threads will run concurrently in the same process.
Obviously, the parallel processing of applications can be implemented under multi-threaded operation, thus improving the performance and throughput of the entire application with higher CPU utilization. In particular, many languages now support multi-core parallel processing technology, but JavaScript is implemented as a single thread.
This is in fact related to its use. As a browser scripting language, JavaScript's primary purpose is to interact with the user and manipulate the DOM. If you manipulate these DOM in a multi-threaded manner, there may be conflicting actions. Assuming that two threads operate on a DOM element at the same time, thread 1 requires the browser to delete the DOM, and thread 2 requires a DOM style change, the browser cannot decide which thread to take action on. Of course, we can solve these conflicts by introducing a "lock" mechanism to the browser, but this can greatly increase the complexity, so JavaScript chooses single-threaded execution from the beginning of the birth.
Also, because JavaScript is single-threaded, you can only perform a specific task at a time and block other tasks from executing. So for time-consuming tasks like I/O, there is no need to wait for them to execute until they are done. Before these tasks are complete, JavaScript can perform other operations down completely, and when these time-consuming tasks are completed, they are handled in a callback manner. These are the innate features of javascript: Async and callbacks.
Of course, for unavoidable time-consuming operations (such as heavy computations, multiple loops), HTML5 proposes a web worker that will use the Worker class to create a new additional thread to load and run a particular JavaScript file in the current JavaScript execution main thread. This new thread does not interfere with and block execution between the main threads of JavaScript, and it provides the interface between this new thread and the data exchange between the main threads of JavaScript in the Web worker: PostMessage and OnMessage events. However, in HTML5 web workers, the DOM cannot be manipulated, and any task that needs to manipulate the DOM needs to be delegated to the JavaScript main thread to execute, so while the HTML5 web worker is introduced, there is still no nature of the rerouting JavaScript single thread.
concurrency mode and event Loop
JavaScript has a model based on "Event Loop" concurrency.
Ah, concurrency? Not that JavaScript is a single thread? Yes, it is a single thread, but concurrency is different from parallelism. The former is logically occurring simultaneously, while the latter is physically occurring simultaneously. Therefore, a single-core processor can also be implemented concurrently.
Concurrency and parallelism
Parallelism is well understood, and the so-called "concurrency" refers to two or more events that occur at the same time interval of two. As the first table, because the computer system has only one CPU, so the ABC three programs from the "micro" is alternately using the CPU, but the alternating time is very short, the user is not aware of, forming a "macro" in the sense of concurrent operation.
Runtime Concept
The following content explains a theoretical model. The modern JavaScript engine has focused on implementing and optimizing several of the concepts described below.
Stack (Stack)
Here is the task that JavaScript is performing. Each task is called a frame (stack of frames).
function F (b) { var a =n; return a+b+35;} function g (x) { var m = 4; return F (m*x);} G (21);
When the above code g
is called, the first frame of the stack is created, and the frame contains the g
parameters and local variables. When g
called f
, the second frame is created and placed above the first frame, and of course, the frame also contains f
the parameters and local variables. When f
it returns, its corresponding frame is out of the stack. Similarly, when g
returning, the stack is empty (the specific stack is the LIFO last-in first-out (LIFO)).
Heap (heaps)
A name used to represent a large, unstructured area of memory in which objects are assigned.
Queue (Queues)
A JavaScript runtime contains a task queue that consists of a series of tasks to be processed. Each task has a corresponding function. When the stack is empty, a task is taken out of the task queue and processed. The processing invokes a series of functions associated with the task (hence creating an initial stack frame). When the task is finished processing, the stack is empty again. (Queue is characterized by FIFO first-in first-out).
In order to facilitate the description and understanding, make the following agreement:
- Stack stack is the main thread
- Queue ranks as task queues (waiting for dispatch to main thread execution)
OK, the above knowledge points help us to clarify the concept of a JavaScript runtime, which is helpful for the next analysis.
Event Loop
This is referred to as event loop because it is implemented in a similar manner as follows:
while (Queue.waitformessage ()) { queue.processnextmessage ();}
As mentioned above, the "task queue" is the queue of an event, if the I/O device completes a task or the user triggers an event (which specifies a callback function), then the related event handler goes to the task queue, and when the main thread is idle, it dispatches the first pending task in the task Queue (FIFO). Of course, for a timer, when it reaches its specified time, the task is inserted into the tail of the task queue.
"Execution to completion"
Each time a task is executed, other tasks are executed. That is, when a function is run, it cannot be superseded and will be completed before other code runs.
Of course, this is also a disadvantage of the event loop: When a task is done too long, the application cannot handle the user's interactions (such as click events) in a timely manner, or even cause the application to collapse. A better solution is to shorten the task completion time, or divide a task into multiple tasks as much as possible.
never block
Unlike other languages, JavaScript is a feature of the event loop that never blocks. I/O operations are typically handled through events and callback functions. Therefore, when an application waits for an IndexedDB or XHR asynchronous request to return, it can still handle other operations, such as user input.
Exceptions are present, such as alert or synchronous xhr, but avoiding them is considered a best practice. Note that exceptions are also present (but are usually implementation errors rather than other reasons).
TimerSome concepts of timers
As mentioned above, the timer inserts the corresponding callback function into the tail of the "task queue" when the specified time is reached. This is the "timer" function.
Timers include two methods of settimeout and SetInterval. Their second argument is to specify that their callback function is deferred and executed after every number of milliseconds.
For the second parameter there are the following areas to note:
- When the second parameter defaults, the default is 0;
- When the specified value is less than 4 milliseconds, it is increased to 4ms (4ms is specified by the HTML5 Standard and 10ms for 2010 and before);
If you understand the above knowledge, then the following code should be no problem for you:
Console.log (1); SetTimeout (function() { Console.log (2);},ten); Console.log (3); // Output: 1 3 2
Learn more about timers
0 delay SetTimeout (func, 0)
0 latency does not mean that the callback function executes immediately. It depends on whether the main thread is currently idle and the task that is waiting in front of the task queue.
Look at the following code:
(function() {Console.log (' This is the start '); SetTimeout (functionCB () {Console.log (' This was a msg from the call back '); }); Console.log (' This is just a message '); SetTimeout (functionCB1 () {Console.log (' This was a msg from the call Back1 '); }, 0); Console.log (' This is the end ');}) ();//The output is as follows: ThisIs the start ThisIs just a message Thisis the endundefined//call the function's return value immediately Thisis a msg from callback Thisis a msg from a callback1
The role of SetTimeout (func, 0)
- Let the browser render the current changes (many browser UI render and JS execution is placed in one thread, thread blocking will cause the interface to not update rendering)
- Re-evaluate "scriptis running too long" warning
- Change the order of execution
Then look at the following code:
<button id= ' do ' > doLongCalc!</button><div id= ' status ' ></div><div id= ' result ' ></div>$(' #do '). On (' click ',function(){ $(' #status '). Text (' Calculating ... ');//The redraw event is triggered here, but is placed in the queue until long () is executed. //without setting the timer, users will not be able to see "Calculating ..." Long();//perform long-time tasks, causing blocking //The timer is set and the user sees "calculating ..." on schedule . //setTimeout (long,50);//After about 50MS, the time-consuming long callback function is inserted at the end of the "task queue", and according to the FIFO principle, it will be dispatched to the main thread execution after redraw });function Long(){ varresult = 0 for(vari = 0; i<1000; i++){ for(varj = 0; j<1000; J + +){ for(vark = 0; k<1000; k++) {result= result + i+j+k}}} $ (' #status '). Text (' calclation done ');//in this case, the statement must be put here, which will make it similar to the behavior of the callback function}
The difference between genuine and pirated setinterval
Everyone may know that through settimeout can imitate the effect of setinterval, below we look at the following code differences:
// use SetTimeout to mimic setintervalsetTimeout (function() {/** / setinterval () (function () {/* */1000);
Maybe you think it's no different. Indeed, when the operations in the callback function are short-term, it is not possible to see what the difference is.
In fact: The setTimeout in the above case will always delay 10ms (or more, but not less) after its callback function executes again, to achieve the setinterval effect, and setinterval always executes 10ms once, Regardless of how long its callback function executes.
Therefore, if the setinterval callback function executes at a time that is equal to or longer than the interval you specify, its callback function is executed together.
You can try running the following code:
var counter = 0; var inittime = new Date (). GetTime (); var timer = setinterval (function () { if (counter===2 if (counter = = = 0 for (var i = 0; i < 1990000000; I++) {; }} console.log ( "+counter+" Times: "+ (new Date (). GetTime ()-inittime) +" MS "); Counter ++);
My Computer Chrome browser input is as follows:
No. 0 Time: Ms 1th: Ms 2nd time: 3008 MS
BrowserThe browser is not a single thread
It says so much about JavaScript, which is single-threaded, and here's the host environment--the browser.
The kernel of the browser is multi-threaded, and they mate with each other under the kernel to keep in sync, and a browser implements at least three resident threads:
- JavaScript engine thread javascript engine is based on the event-driven single-threaded execution, JS engine has been waiting for the task queue of the arrival of the task, and then to deal with, the browser whenever there is only one JS thread running JS program.
- GUI Render thread The GUI rendering thread is responsible for rendering the browser interface, which executes when the interface needs to be redrawn (Repaint) or when a return (reflow) is caused by an operation. However, it is important to note that the GUI rendering thread is mutually exclusive to the JS engine, and when the JS engine executes, the GUI thread is suspended, and the GUI update is saved in a queue until the JS engine is idle and executed immediately.
- browser event triggers thread event triggering thread, when an event is triggered, the thread adds the event to the " Task queue "at the end of the team, waiting for the JS engine processing. These events can come from code blocks currently executing by the JavaScript engine, such as settimeout, other threads from the browser kernel such as mouse clicks, Ajax asynchronous requests, and so on, but since JS is single-threaded, all of these events have to be queued for the JS engine to process.
In Chrome, each tab is a process in order to prevent the entire browser from being affected by a page collapse. Of course, for the same domain name tabs are able to communicate with each other, in particular, to see the browser cross-label communication. There are a lot of processes in the chrome design, and using interprocess communication to do the synchronization between them, so this is one of the quick magic of chrome. Requests for Ajax also require special threads to execute, and when an AJAX request needs to be sent, the browser opens a new thread to execute the HTTP request, which does not block the execution of the JavaScript thread, and when the HTTP request state changes, the corresponding event is placed as a callback into the " Waiting to be executed in the task queue.
Look at the following code:
function () { console.log ("click")} for(100000000; i++);
Explain the code: first registers a click event with the document and then executes a time-consuming for loop, where you can try clicking on the page before the end of the For loop. When the time-consuming operation is finished, the console console outputs the "click" Statement of the event before it is clicked. This depends on the proof that the click event (and all other events) is triggered by an additional individual thread, and the event triggers the callback function to the end of the "task queue" and waits for the JavaScript main thread to execute.
Summary
- JavaScript is single-threaded and can only perform specific tasks at the same time. and the browser is multi-threaded.
- asynchronous tasks (various browser events, timers, etc.) are added to the task queue first (when the timer reaches its specified parameters). When the stack stack (JS main thread) is empty, it reads the first task (team head) of the queue (task queue) and executes.
JavaScript implements single-threaded execution to avoid complexity. Now JavaScript is becoming more and more difficult, and of course it's a fascinating place for JavaScript.
References:
- A detailed explanation of JavaScript running mechanism: Another talk about event Loop
- JavaScript single thread and browser event loop brief
- JavaScript is a single-threaded in-depth analysis
- Concurrency model and Event Loop
- Also talk about SetTimeout
- Single thread of JavaScript
Some of the things that are going on in JavaScript single thread