A detailed explanation of JavaScript running mechanism: Another talk about event Loop

Source: Internet
Author: User
Tags setinterval

Original Address: http://www.ruanyifeng.com/blog/2014/10/event-loop.html

A year ago, I wrote an article, "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.

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.

(updated October 13, 2014: This article has made a big change, reflecting my current understanding.) For more explanations and examples of settimeout, see the JavaScript Standard reference tutorial I'm Writing. )

(updated on October 11, 2014: Pauling A commentary on this article, the author pointed out in detail the existence of the erroneous statement, suggested Reading. )

Why is JavaScript a single thread?

One of the main features of the JavaScript language is single-threaded, meaning 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.

The single thread of JavaScript is related to its purpose. 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.

second, the task queue

A single thread means that all tasks need to be queued, and the previous task is completed before the latter one is Executed. If the previous task takes a long time, the latter task has to Wait.

If the queue is because of large computational capacity, the CPU is not busy, but also forget, but many times the CPU is idle, because the IO device (input) is very slow (such as the Ajax operation from the network to read data), have to wait for the results, and then down to Execute.

The designer of the JavaScript language realizes that at this point the main thread can completely ignore the IO device, suspend the waiting task, and first run the task that is in the Queue. Wait until the IO device returns the result, and then go back and put the suspended task on HOLD.

thus, All tasks can be divided into two types, one synchronization task (synchronous) and one asynchronous task (asynchronous). A synchronization task is a task that is queued on the main thread to perform the latter task only if the previous task is completed, and the asynchronous task refers to a task that goes into the task queue without entering the main thread, and only the task queue notifies the main thread that an asynchronous task can Execute. The task will not go into the main thread Execution.

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.) )

(1) all synchronization 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. As long as the asynchronous task has a running result, an event is placed in the task Queue.

(3) once all the synchronization tasks in the "execution stack" have been executed, the system reads the "task queue" to see what events are in it. Those corresponding asynchronous tasks, so end the wait state, go to the execution stack, and start Execution.

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

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.

III. events and Callback functions

The task queue is 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.

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. An asynchronous task must specify a callback function that executes the corresponding callback function when the main thread starts executing an asynchronous TASK.

A "task queue" is a FIFO data structure, preceded by events, that are first read by the main thread. The main thread of the read process is basically automatic, as long as the execution stack is emptied, the first event on the "task queue" automatically enters the main thread. however, due to the "timer" feature mentioned later, the main thread must first check the execution time, and some events will return to the main thread only by the specified Time.

Iv. Event Loop

The main thread reads events from the task queue, and the process is cyclic, so the whole mechanism is called event Loop.

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

, 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 (the synchronization task) is always executed before the task queue (asynchronous Task) is Read. Take a look at the example below.

    var req=NewXMLHttpRequest(); Req.Open(' GET '.onload = function  ({ }.onerror Span class= "token operator" >= function  () {} .   

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=NewXMLHttpRequest(); Req.Open(' GET 'send (.onload = function Span class= "token punctuation" > ({}.onerror = function  ( {} 

That is, 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 the events that place an asynchronous task, the task queue can also place 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< Span class= "token punctuation" > ({consolelog (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 ( Span class= "token keyword" >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.

In summary, setTimeout (fn,0) means that a task is specified to execute at the earliest available idle time of the main thread, that is, to execute as early as Possible. It adds an event at the end of the task queue, so it will not be executed until both the synchronization task and the task queue existing events are Processed.

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 ().

Vi. event Loop for Node. JS

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).

According to this, Node. JS runs the following MECHANISM.

(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.

In addition to the two methods of settimeout and setinterval, Node. JS also provides two other methods related to the task Queue: 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 event Loop (the main thread reads the task queue). In other words, it specifies that the task always occurs before all asynchronous tasks. The Setimmediate method adds an event at the end of the current task queue, meaning that the task it specifies is always executed at the next event loop, much like the settimeout (fn, 0). Take a look at the following example (via stackoverflow).

Process.Nexttick(functionA(){console.Log(1); Process.Nexttick(functionB(){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(functionA(){console.Log(1);Setimmediate(functionB(){console.Log(2);}) ;}; Settimeout (function  Timeout ({ Console. Log ( ' TIMEOUT fired ' }0"          

In the above code, setimmediate and settimeout (fn,0) each added a callback function A and timeout, which are triggered at the next event loop. so, which callback function executes first? The answer is not sure. The result may be 1--timeout fired--2, or a TIMEOUT fired--1--2.

confusingly, the Node. JS document says that setimmediate specifies a callback function that always precedes Settimeout. In fact, this happens only when a recursive invocation occurs.

Setimmediate(function(){Setimmediate(functionA(){console.Log(1);Setimmediate(functionB(){console.Log(2);});});settimeout (function Span class= "token function" >timeout ({console. Log ( ' TIMEOUT fired ' }0) ;} ; 1//TIMEOUT fired//2      

In the above code, Setimmediate and settimeout are encapsulated in a setimmediate, and its running result is always 1--timeout fired--2, when function A must be triggered in front of TIMEOUT. As for the 2 row behind timeout fired (that is, function B is triggered after timeout), because setimmediate always registers events with the next event loop, so functions A and timeout are executed in the same loop, and function B executes in the next loop.

We get an important difference between Process.nexttick and setimmediate: multiple Process.nexttick statements are always executed at the current execution stack, and multiple setimmediate may require multiple loops to Execute. 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!

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).

Finish

A detailed explanation of 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.