JavaScript’s concurrency model is based on “event loops”
JavaScript runtime concepts
Visual description
The stack
The function call forms a stack frame
function foo(b) {
var a = 10;
return a + b + 11;
}
function bar(x) {
var y = 3;
returnfoo(x * y); } console.log(bar(7)); / / 42Copy the code
- When bar is called, the first frame is created that contains bar parameters and local variables
- When foo is called in bar, a second frame is created and pressed on top of the first frame, which contains foo’s arguments and local variables
- When Foo returns, the topmost frame is ejected from the stack (leaving bar’s call stack), and when bar returns, the stack is empty
The heap
Objects are allocated in a heap, which represents a large, unstructured area of memory
The queue
A JavsScript runtime contains a queue of messages to be processed; Each message is associated with a function that processes the message.
At some point during the event loop, the runtime processes messages in the queue starting with the first message to be queued. To do this, the queued message is removed from the queue and the function associated with it is called as an input parameter. As mentioned earlier, calling a function always creates a new stack frame for it.
Function processing continues until the stack is empty and unknown again; The event loop will then process the next message in the queue (if any)
Event loop
It is called an event loop because it is often implemented in a way like the following:
while(queue.waitForMessage()) {
queue.processNextMessage();
}
Copy the code
If there is no message, queue.waitFormessage () waits synchronously for the message to arrive
“Execution to completion”
After each message is executed in its entirety, other messages are executed
This provides some excellent features for program analysis, including that when a function executes, it is never preempted and runs completely (and can modify the data on which the function operates) before other code runs.
The downside of this model is that when a message takes too long to complete, the Web application can’t handle user interactions, such as clicking or scrolling. A good practice is to shorten message processing and, where possible, crop one message into multiple messages.
Add a message
In the browser, when an event occurs and an event listener is bound to the event, messages are added to the queue at any time. If there is no event listener, the event is lost. So clicking on an element with a click event handler adds a message, and other events are similar.
<div id="box"></div>
var box = document.getElementById('box');
box.onClick = function() { console.log('click'} // bind event listener box.onClick = null // Without event listener, event will be lostCopy the code
setTimeout
The setTimeout function takes two parameters: the message to be queued and an optional delay (default: 0). This delay represents the minimum delay for the message to actually be enqueued. If there are no other messages in the queue, they will be processed immediately after this delay has elapsed. However, if there are other messages, the setTimeout message must wait for the other messages to finish processing.
setTimeout(function() {
console.log("zhixing") 200}},Copy the code
Therefore, the second parameter (200) only represents the minimum delay time, not the exact wait time.
const s = new Date().getSeconds();
setTimeout(function() {// output"2", indicating that the callback does not execute console.log("Ran after " + (new Date().getSeconds() - s) + " seconds");
}, 500);
while(true) {
if(new Date().getSeconds() - s >= 2) {
console.log("Good, looped for 2 seconds");
break; }}Copy the code
Zero delay
Zero latency does not mean that the callback will execute immediately. SetTimeout with 0 as the second argument does not mean that the callback is called immediately after 0 milliseconds.
The wait time depends on the number of messages waiting to be processed in the queue.
Basically, setTimeout needs to wait until all messages in the current queue have been processed before executing, even if the time specified by the second parameter has elapsed.
(function() {
console.log('This is the beginning');
setTimeout(function cb() {
console.log('This is the message from the first callback.');
});
console.log('This is a message.');
setTimeout(function cb1() {
console.log('This is a message from the second callback.');
}, 0);
console.log('This is the end'); }) (); //"This is the beginning."
// "This is a message."
// "This is the end."
// "Here's the message from the first callback."
// "Here's the message from the second callback."
Copy the code
Multiple runtimes communicate with each other
A Web worker or a cross-domain iframe has its own stack, heap, and message queue. Two different runtimes can communicate only through the postMessage method. If another runtime listens for message events, this method adds messages to that runtime.
Never block
One very interesting feature of the event loop model is that, unlike many other languages, JavaScript never blocks. Processing I/O is typically performed through events and callbacks, so while an application is waiting for an IndexedDB query to return or an XHR request to return, it can still handle other things, such as user input.
Legacy surprises exist, such as Alert or via XHR, but they should be avoided as much as possible
I am just MDN porter (MDN address) developer.mozilla.org/zh-CN/docs/…