An explanation of the "Pauling commentary" JavaScript running mechanism: Another talk about event Loop

Source: Internet
Author: User
Tags setinterval

PS: I first look at the discussion of the Masters, we have to read a lot of ~  others said: "I did not think the commentary on where to go, only the sense of fault." For example, synchronous asynchronous introduction, there is no big mistake, such as the OS operation in node graph, it can be guessed that it refers to synchronous operation (Nature does not go to the event loop); As for watcher, it is clearly a feature of realization. Even with the same queue implementation is not possible " " original post: http://www.ruanyifeng.com/blog/2014/10/event-loop.html  Ruan Yi Feng "a year ago, I wrote a What is Event Loop? , and talked about my understanding of the event loop.   Last month, I happened to see Philip Roberts's Speech "help, I ' M stuck in an Event-loop". It is only embarrassing to find that their understanding is wrong. I decided to rewrite this topic to describe the internal operating mechanism of the JavaScript engine in a detailed, complete, and correct manner. Here's my rewrite.   "The JavaScript engine's internal operating mechanism has no half-dime relationship with event loop. "The mistake here is to distinguish between the JavaScript execution environment and the execution engine, which usually refers to the virtual machine, which is V8 for node, V8 for Chrome, and JavaScript Core for Safari, It's SpiderMonkey for Firefox. JavaScript has a lot of execution environment, which says a variety of browsers, Node, Ringo and so on. The former is the engine and the latter is the runtime. "For the engine, what they want to achieve is the ECMAScript standard." For what is event loop, they are not interested and don't care. "To be precise, it should be the runtime's execution mechanism."   Before entering the text, a message is interrupted. My new book "ECMAScript 6 Primer" published (Copyright page, page 1, page 2), coated paper full-color printing, very beautiful, but also with index (of course, the price is slightly more expensive than similar books a little). Preview and purchase click here.   "new book or support"   One, why is JavaScript a single thread? One of the major features of the  javascript language is the single thread, which means that only one thing can be done at the same time. So why can't javascript have multiple threads? This can improve the efficiency AH.  javascript's single thread, with its useAbout. As a browser scripting language, JavaScript's primary purpose is to interact with the user and manipulate the DOM. This determines that it can only be single-threaded, otherwise it can lead to complex synchronization problems. For example, assuming that JavaScript has two threads at the same time, one thread adds content to one of the DOM nodes, and the other thread deletes the node, which thread should the browser take precedence over?   So, to avoid complexity, JavaScript is a single thread from birth, which has become a core feature of the language and will not change in the future.   to take advantage of the computational power of multicore CPUs, HTML5 proposes a web worker standard that 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 new standard does not change the nature of JavaScript single threading.   "This is not a big problem, thank you, teacher Ruan" second, the task queue   single-threaded means that all tasks need to be queued, the previous task is completed before a task is executed. If the previous task takes a long time, the latter task has to wait.   If the queue is because the calculation of large, CPU busy, but also forget, but a lot of time the CPU is idle, because the IO device (input) is very slow (such as the Ajax operation from the network reading data), have to wait for the results to come out, and then down execution. The designer of the  javascript language realizes that at this point the CPU can completely ignore the IO device, suspend the task in wait, and run the task in the back row first. Wait until the IO device returns the result, and then go back and put the suspended task on hold.   "This has nothing to do with Brendan Eich. Process in the processing of IO operations, the operating system more semi-automatic cutting the CPU to other processes used "  Then, JavaScript has two ways of doing it: one is that the CPU executes sequentially, the previous task ends, and then the next task, which is called synchronous execution The other is that the CPU skips a long wait task, first processing the later task, which is called asynchronous execution. Programmers choose which method to use.   "Pure RIP. "Give the CPU what instructions it executes, and what CPU skips the long waiting time." In the final analysis, Mr. Ruan did not understand what is called asynchrony. "  Specifically, the operating mechanism for asynchronous execution is as follows. (Synchronous execution is also true because it can be treated as asynchronous execution without an asynchronous task.)   "Above this sentence shows that not only do not understand what is asynchronous, but also do not understand what is synchronous. 】

(1) All tasks are performed on the main thread, forming an execution stack (execution context stack).

(2) In addition to the main thread, there is a task queue. The system puts the asynchronous task in the task queue and then resumes the subsequent task.

(3) Once all the tasks in the "execution stack" have been executed, the system reads the "Task queue". If this time, the asynchronous task has completed the wait state, it will go from the "task queue" into the execution stack, resume execution.

(4) The main thread constantly repeats the third step above.

"The above paragraph is about the event loop," said the preliminary. But Async doesn't really matter with the event loop. To be precise, event loop is a mechanism for implementing Asynchrony "" in general, operations are divided into two steps: making a call and getting results. The call is made immediately and the result is synchronized. Making a call, but not getting the result immediately, requires extra action to get the expected result to be asynchronous. Synchronization is called after the call waits until the result is returned. Asynchronous is called after, can not directly get results, through a series of means to finally get the results (after the call, the middle of the time to get results can intervene in other tasks). "The series of tools mentioned above are actually methods of implementing async, including the event loop. And polling, events, and so on. The so-called poll: After you pay at the cashier, sit in the position to ask the waiter your dish is done. The so-called (event): After you pay at the cashier, you don't have to keep asking, the food is ready, the waiter will tell you. "is the main thread and the task queue.


As long as the main line Cheng, will read "task queue", this is the operation mechanism of JavaScript. This process is repeated.

"The operating mechanism of the JavaScript run environment is not the operating mechanism of JavaScript." The "three, event and callback functions" task queue is essentially a queue of events (which can also be understood as a queue of messages), and the IO device completes a task by adding an event in the task queue that indicates that the associated asynchronous task can enter the execution stack. The main thread reads the "Task queue", which is what events are read inside. The task queue is neither a queue for events nor a queue for messages. The task queue is everything you call on the main thread. "The so-called event-driven, is to abstract everything into events." IO operation completion is an event, the user clicks the mouse is an event, Ajax completed is an event, a picture loading completed is an event "" a task does not necessarily produce events, such as getting the current time. "" When an event is generated, the event is placed in the queue, waiting to be processed "

Events in the task queue, in addition to the IO device events, include some user-generated events (such as mouse clicks, page scrolling, and so on). Whenever a callback function is specified, these events go into the task queue and wait for the main thread to read.

The so-called "callback function" (callback) is the code that will be hung up by the main thread. The asynchronous task must specify a callback function that executes when the asynchronous task returns to the execution stack from the task queue. "They have not been executed at all, so why hang up?" he asked. "" The asynchronous task does not necessarily have to be a callback function. "There's never been any execution stack." The main thread is always in execution. The main thread will constantly check the event queue "task queue" is a first-in-a-out data structure, in front of the event, priority to return to the main thread. The main thread's read process is basically automatic, as long as the execution stack is emptied, the first event on the "task queue" automatically returns to the main thread. However, due to the "timer" feature mentioned later, the main thread has to check the execution time, and some events must be returned to the main thread at a specified time. "The first occurrence of the event is processed first." Always on the main thread, no return main thread said "" Some events also do not have to be executed at the specified time, sometimes there is no way to execute at the specified time "four, the event loop main thread from the" task queue "to read events, this process is cyclic, so the whole operation mechanism is called the event Loop (event loop). The event-driven implementation process is mainly done by the event loop. When the process starts, it enters the main loop. The process of the main loop is to continuously read events from the event queue. If the event has an associated handle (that is, registered callback), the handle is executed. An event does not necessarily have a callback "

To get a better understanding of the event Loop, see (quoted from Philip Roberts's speech, "Help, I ' m stuck and an Event-loop").


"So the callback queue above is actually the event queue"

, when the main thread runs, the heap (heap) and stack (stack) are generated, and the code in the stack calls various external APIs, which include various events (Click,load,done) in the task queue. As soon as the code in the stack finishes executing, the main thread reads the task queue and executes the callback function that corresponds to those events.

The code in the execution stack is always executed before the task queue is read. Take a look at the example below.

    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 that the AJAX operation sends data to the server, which is an asynchronous task that means that the system will not read the task queue until all the code for the current script has been executed. Therefore, it is equivalent to the following notation.

    var req = new XMLHttpRequest();    req.open(‘GET‘, url);    req.send();    req.onload = function (){};        req.onerror = function (){};   
"The equivalent of a fart." This call actually has a default callback function, after the end of Ajax, execute the callback function, check the status of the callback function, decide to call onload or onerror. So as long as the two properties are set before the callback function executes "in other words, specifying the part of the callback function (onload and onerror) does not matter before or after the Send () method because they are part of the execution stack and the system always executes them before it reads the" task queue. " Five, timer

In addition to placing asynchronous tasks, the task queue also has the function of placing timed events that specify how much time some code executes. This is called the timer function, which is the code that executes periodically.

The timer function is mainly by settimeout () and setinterval () These two functions to complete, their internal operation mechanism is exactly the same, the difference is that the former specified code is one-time execution, the latter is repeated execution. The following main discussion settimeout ().

SetTimeout () accepts two parameters, the first is a callback function, and the second is the number of milliseconds to defer execution.

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

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

If you set the second parameter of settimeout () to 0, the callback function specified immediately (0 millisecond interval) is executed as soon as the current code finishes executing (execution stack emptying).

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

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

The HTML5 standard specifies the minimum value (minimum interval) of the second parameter of the settimeout (), which is not less than 4 milliseconds, and is automatically incremented if it is below this value. Prior to this, the older versions of the browser set the minimum interval to 10 milliseconds.

In addition, the changes to those dom, especially those involving page re-rendering, are usually not executed immediately, but once every 16 milliseconds. The effect of using requestanimationframe () is better than settimeout ().

It is important to note that setTimeout () simply inserts the event into the "task queue" and must wait until the current code (execution stack) finishes executing, before the main thread executes the callback function it specifies. If the current code takes a long time, it may take a long time, so there is no guarantee that the callback function will be executed at settimeout (). "Timers are not exceptions. When the point is reached, an event (timeout event) is formed. The difference is that the general event is generated by the underlying system or the thread pool, but the timer event is the event loop that checks the system time to determine if the time is reached to generate the event "VI, node. js Event Loop

node. JS is also a single-threaded event Loop, but it operates differently from the browser environment.

Take a look at the following (author @busyrich).


"With my understanding of node, the picture above is also wrong. The OS operation is not in that position, but behind the event loop. Event queue in the middle of event loop "" Js-> v8-> node binding-> (event loop), worker threads/poll-> blocking opera tion <-<-<--(event loop) < —————— event < —————— "according to node. JS, the following are the operating mechanisms.

(1) V8 engine parsing JavaScript script.

(2) After parsing the code, call the node API.

(3) The LIBUV Library is responsible for node API execution. It assigns different tasks to different threads, forms an event loop, and asynchronously returns the execution results of the task to the V8 engine.

(4) The V8 engine returns the result to the user.

"It is not a different task to assign to different threads at all. The thread pool (Unix) is used only for disk IO operations. "" In node, the asynchronous operation of disk I/O is as follows: "" encapsulates the call into an intermediate object, gives it to the event loop, and then directly returns "" the intermediate object is thrown into the thread pool, waiting for execution to finish, the data is put into the event queue, forming the event "" loop execution, processing the event. Get the event's correlation function (callback) and the data, execute it "" and then the next event, continue looping "in addition to the settimeout and SetInterval methods, node. JS also provides two additional" task queues " Related methods: Process.nexttick and Setimmediate. They can help us deepen our understanding of the "task queue".

The Process.nexttick method can trigger a callback function----the end of the current execution stack----the next time the main thread reads the task queue. In other words, it specifies that the task always occurs before all asynchronous tasks. The Setimmediate method is to trigger a callback function at the end of the current task queue, meaning that the task it specifies is always executed the next time the main thread reads the task queue, much like the settimeout (FN, 0). Take a look at the following example (via StackOverflow).

process.nextTick(function A() {  console.log(1);  process.nextTick(function B(){console.log(2);});});setTimeout(function timeout() {  console.log(‘TIMEOUT FIRED‘);}, 0)// 1// 2// TIMEOUT FIRED

In the above code, the callback function specified by the Process.nexttick method is always triggered at the end of the current "execution stack", so not only function A is executed before the callback function specified by settimeout, but function B is also executed before timeout. This means that if there are multiple Process.nexttick statements (whether or not they are nested), they will all be executed on the current "execution stack".

Now, look at setimmediate.

setImmediate(function A() {  console.log(1);  setImmediate(function B(){console.log(2);});});setTimeout(function timeout() {  console.log(‘TIMEOUT FIRED‘);}, 0)// 1// TIMEOUT FIRED// 2

In the above code, there are two setimmediate. The first setimmediate specifies that the callback function A is triggered at the end of the current task queue (when the next event loop), and then settimeout also specifies that the callback function timeout is triggered at the end of the current "task queue", so the output results in a timeout Fired in the back of 1. As for the 2 row behind the timeout fired, it is because of another important feature of Setimmediate: an "event loop" can only trigger a callback function specified by Setimmediate.

We get an important difference: multiple Process.nexttick statements are always executed at once, and multiple setimmediate need to be executed more than once. In fact, this is the reason for the addition of the Setimmediate method to node. JS version 10.0, otherwise recursive calls to Process.nexttick like the following will be endless and the main thread will not read the event queue at all! "The 10.0 version doesn't have to be corrected."
process.nextTick(function foo() {  process.nextTick(foo);});

In fact, now if you write a recursive process.nexttick,node.js will throw a warning and ask you to change to Setimmediate. Also, since the callback function specified by Process.nexttick is triggered in the event loop, and Setimmediate specifies the next "event loop" trigger, it is clear that the former is always older than the latter and the execution is high (because the task queue is not checked).

The difference between setimmediate and settimeout (fn,0) is that setimmediate always executes in front of settimeout, except when the main thread enters event loop for the first time. Take a look at the example below.

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

The result of the above code is not deterministic, it could be 1, 2, or maybe 2, 1, even if the settimeout and setimmediate two function interchange position. Because these codes are run before the main thread reads the event loop for the first time. However, if you put this code in Setimmediate, the result is different.

setImmediate(function () {  setTimeout(function () {     console.log(‘1‘);  },0);  setImmediate(function () {     console.log(‘2‘);  })})
The result of the above code is always 2,1, because after entering the event loop, Setimmediate is triggered before settimeout. "There will still be 1 or 2 of cases. Oh. Try it "(end)" To be exact, there must be very, very many events in the event-driven system. If the event is generated, it is necessary to deal with the main loop, which inevitably causes the main thread to be busy. For the application layer code, there must be a lot of things that don't care (like just the Click event, not the timer event). This can lead to a certain waste. An important concept not mentioned in this article is watcher. Observers. "In fact, not all events are placed in a queue." "" Different events, placed in different queues. "" When we do not use the timer, we do not have to care about the timer event this queue "" When we make a timer call, we first set up a timer watcher. During the event loop, the watcher is called to check whether it generates an event on the event queue (compared to the time) "" When we are doing disk IO, we first set up an IO watcher, and when disk IO is complete, an event is added to the event queue for that Io watcher. Events are processed from the watcher during the event loop. After processing the existing events, processing the next watcher "" After checking all watcher, go to the next check "" not concerned about a certain kind of event, then there is no relevant watcher "" Finally, if there is a problem, thank you for pointing out "

An explanation of the "Pauling commentary" JavaScript running mechanism: Another talk about event Loop

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.