Previous words
This article describes the event loops in JavaScript in detail Event-loop
Thread
JavaScript is a single-threaded language, meaning that you can only do one thing at a time. While this single-threaded feature is relevant to its purpose, as a browser scripting language, JavaScript's primary purpose is to interact with the user, as well as 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?
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 doesn't change the nature of JavaScript single threading
Queued
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
var i, t = date.now () for (i = 0; i < 100000000; i++) {}console.log (Date.now ()-T)//238
Like above, if the queue is because of the high computational capacity, the CPU is not busy, but also forget
However, if the network request is not appropriate. It is unwise to wait in line for a network-requested resource when it is unpredictable to return.
Synchronous and asynchronous
Therefore, the task is divided into synchronous tasks and asynchronous tasks
Synchronization
If the caller is able to get the expected result (i.e., the expected return value or see the desired effect) when the function returns, then the function is synchronous
Math.sqrt (2); Console.log ('Hi');
When the first function returns, it gets the expected return value: The square root of 2; When the second function returns, you see the expected effect: a string is printed on the console
So the two functions are synchronous.
Asynchronous
If the caller is not able to get the expected result when the function returns, but it needs to be obtained in the future by some means, then the function is asynchronous
Fs.readfile ('foo.txt'UTF8', function (err, data) { Console.log (data);});
In the above code, we want to fs.readFile
read the contents of the file Foo.txt through the function and print it out. But fs.readFile
when the function returns, we expect the result to not happen, but to wait until all the files have been read. It could take a long time if the file is large.
So, the Fs.readfile function is asynchronous.
It is because JavaScript is single-threaded, and asynchronous is easy to implement non-blocking, so in JavaScript for time-consuming operations or the operation of uncertain times, the use of asynchronous is a necessary choice
Asynchronous explanation
As you can see from the above, the 异步函数
call is actually done quickly. But there are many steps behind the asynchronous operation, the notification main thread, the main thread call callback function, and so on. We call the whole process 异步过程
. The invocation of an asynchronous function is only a small part of the entire asynchronous process
An asynchronous process is usually this: the main thread initiates an asynchronous request, and the asynchronous task receives the request and tells the main thread that it has received (the asynchronous function returns); The main thread can continue executing the following code while the asynchronous operation begins, and the main thread is notified after execution is completed, and the main thread receives the notification and performs a certain action ( Call callback function)
Therefore, an asynchronous process consists of two features: a registration function and a callback function, where the registration function is used to initiate the asynchronous process, and the callback function is used to process the result
In the following code, where settimeout is the initiating function of the asynchronous procedure, FN is the callback function
);
There is a very important question, how is an asynchronous operation done? For different types of asynchronous tasks, the standard of operation completion is different
"Asynchronous Type"
Generally, there are three types of asynchronous tasks:
1, ordinary events, such as click, resize, etc.
2. Loading of resources, such as load, error, etc.
3, timers, including setinterval, settimeout, etc.
The following are examples of these three types, the following code, the mouse click on the div, the task execution is completed
Div.onclick = () = { console.log ('click')}
In the following code, the readystate value of the Xhr object is 4, which means that all response data has been received, representing the completion of the task execution
Xhr.onreadystatechange = function () { if4) { if { // actual operation result.innerhtml + = xhr.responsetext; }}}
The following code, after 1s, represents the completion of a task execution
SetTimeout (() = { console.log ('timeout')}, +)
For synchronous tasks, it can be executed sequentially, but for asynchronous tasks, each task executes differently and the point in time of execution is different, how does the main thread regulate asynchronous tasks? This is where Message Queuing is used.
"Message Queuing"
Some articles call Message Queuing a task queue, or an event queue, in short, a queue that is related to an asynchronous task
To be sure, it is the first-in, first-out data structure of the queue, and the queue is similar, and which asynchronous operation is completed early, is in front. Whenever an asynchronous operation starts executing, it can be queued to the message queue as long as the asynchronous operation completes
This allows the main thread to get a message from the message queue and execute it when it is idle
What exactly is the message in Message Queuing? The concrete structure of the message is of course related to the specific implementation. But for the sake of simplicity, it can be assumed that the message is the callback function that was added when registering the asynchronous task.
Visual description
The mechanism by which JavaScript regulates synchronous and asynchronous tasks is called event loops, and the visual description of the event loop mechanism is first seen
Stack
A function call forms a stack frame
function Foo (b) { var a = ten; Return a + B + one;} function bar (x) { var y = 3; return foo (x * y);} Console.log (Bar (7));
When called bar
, the first frame is created, bar
and the arguments and local variables are included in the frame. When bar
called foo
, the second frame is created and pressed onto the first frame, and the frame contains foo
the parameters and local variables. When foo
returned, the topmost frame is ejected from the stack ( bar
the call frame of the function is left). When you bar
return, the stack is empty.
Heap
Objects are allocated in a heap, which is used to represent a large part of a non-structured memory area
Queue
A JavaScript runtime contains a pending message queue. Each message is associated with a function. When the stack has enough memory, a message is fetched from the queue for processing. This process involves invoking the function associated with the message (and thus creating an initial stack frame). When the stack is empty again, it means that the message processing is over.
Event Loops
The following is a detailed description of the event loop. , when the main thread runs, the heap and stack are generated, the code in the stack calls various external APIs, and after the asynchronous operation completes, it is queued in the message queue. As soon as the code in the stack finishes executing, the main thread reads the message queue and executes the callback function that corresponds to the asynchronous task in turn.
The detailed steps are as follows:
1. All synchronization tasks are performed on the main thread to form an execution stack
2. There is also a "message queue" outside the main thread. Queues the message queue as long as the asynchronous operation finishes executing
3, once all synchronization tasks in the execution stack are executed, the system reads the asynchronous task in the message queue sequentially, and the asynchronous task is read to end the waiting state, enter the execution stack, and start executing
4, the main thread constantly repeat the third step above
Cycle
From the point of view of code execution order, the program first executes code in code order, encounters a synchronization task, executes immediately, and encounters an asynchronous task that simply invokes an asynchronous function to initiate an asynchronous request. At this point, the asynchronous task begins an asynchronous operation that is queued in the message queue after execution completes. After the program executes in code order, query the message queue for waiting messages. If so, the messages are placed in the execution stack from the message queue in order. Once executed, the message is then retrieved from the message queue and then executed and repeated repeatedly.
Because the main thread is repeatedly getting the message, executing the message, then fetching the message, and then executing. So, this mechanism is called the event loop
This is probably the case with code:
while (Queue.waitformessage ()) { queue.processnextmessage ();}
If no messages are currently queue.waitForMessage
waiting for the synchronization message to arrive
Event
Why is it called an event loop? Instead of a task loop or message loop. The reason is that each message in the message queue actually corresponds to an event
Dom operations correspond to DOM events, and the resource load operation corresponds to the Load event, and the timer operation can be seen as a corresponding "time-to-go" event
Instance
An example is given below to explain the event loop mechanism.
Console.log (1= () = {Console.log ('click')}console.log ( 2 = = {Console.log ('timeout')}, +)
1, executes the first line of code, the first line is a synchronization task, console display 1
2, executes the second line of code, the second line is an asynchronous task, initiates an asynchronous request, can perform a mouse click at any time asynchronous operation
3, executes the third line of code, the third line is a synchronization task, console display 2
4, executes the fourth line of code, line fourth is an asynchronous task, initiates an asynchronous request, executes a timer task after 1s
5, assume that the execution of the fourth line of code in 1s, the mouse click, the task in the message queue to the first
6, from the execution of the fourth line of code 1s, the timer task to the message queue to the second place
7. Now that the synchronization task is completed, the asynchronous task is placed in the execution stack from the message queue in the order of execution
8. The console displays ' click ', ' Timeout ' in turn
9, after a period of time, and executed a mouse click, because the message queue is empty, the mouse task in the message queue to the first
10. After the synchronization task is executed, the asynchronous task is placed in the execution stack from the message queue in the order of execution.
11. The console displays ' click '
"Asynchronous Process"
The following is an example to explain a complete asynchronous process
Div.onclick = function fn () {Console.log ('click')}
1. The main thread initiates an asynchronous request by calling the asynchronous function Div.onclick
2, in a moment, perform an asynchronous operation, that is, the mouse click
3. Next, the callback function fn is queued in the message queue
4. The main thread reads FN from the message queue to the execution stack
5. Then execute the Code console.log (' click ') inside FN on the execution stack
6, then, the console display ' click '
Synchronous variable Asynchronous
After each message is fully executed, other messages are executed. This provides some excellent features, including that it cannot be preempted whenever a function is run, and runs completely before other code runs
One drawback of this model is that when a message takes too long to complete, the Web app cannot handle the user's interactions, such as tapping or scrolling
As a result, a common optimization for this situation is synchronous asynchronous
An example is to create a WEBQQ QQ friends list. There are usually hundreds or thousands of friends in the list, and if a friend is using a node to render the list in a page, you might want to create hundreds or thousands of nodes in the page at once.
Adding DOM nodes to a page in a short period of time will obviously make the browser too much, and the results are often the result of browser lag or even suspended animation. The code is as follows:
varary = []; for(vari =1; I <= +; i++) {Ary.push (i); //Suppose ary loaded 1000 friends ' data};varRenderfriendlist =function (data) { for(vari =0, L = data.length; I < L; i++ ){ vardiv = document.createelement ('Div' ); Div.innerhtml=i; Document.body.appendChild (DIV); }};renderfriendlist (ary);
One solution to this problem is the array chunking technique, where the following Timechunk function allows the creation of nodes to be done in batches, such as creating 1000 nodes in 1 seconds, instead of creating 8 nodes every 200 milliseconds
function Chunk (array,process,context) { setTimeout (function () { /// Remove the next entry and process var item = array.shift (); Process.call (Context,item); // If you have an entry, set another timer if 0 { setTimeout (Arguments.callee); }};
var data = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ];function Printvalue (item) { var div = document.getElementById ( " ' ); div.innerhtml + = Item + " <br> " ;} Chunk (Data.concat (), printvalue);
The importance of array chunking is that it can separate the processing of multiple items on the message queue, giving other asynchronous task execution opportunities after each item is processed, which may prevent long-running script errors. Once a function takes more than 50ms of time to complete, it's best to see if you can split the task into a series of small tasks that use timers
In-depth understanding of event loops in JavaScript event-loop