Understanding JS Event Cycle _javascript Skills

Source: Internet
Author: User
Tags http request message queue

With the popularity of JavaScript as a scripting language for Web browsers, it is useful to have a basic understanding of its event-driven interaction model and its differences with the request-response model common in Ruby, Python, and Java. In this article, I'll explain some of the core concepts of JavaScript concurrency models, including their event loops and message queues, in the hope that you can improve your understanding of a language that you may already be using but may not fully understand.

Who is this article addressed to?

This article is for Web developers who use or plan to use JavaScript on the client or server side. If you have mastered the cycle of events, most of this article will be familiar to you. For those who are not yet proficient, I hope to provide you with a basic understanding that will help you to read and write everyday code better.

Non-blocking I/O

In JavaScript, almost all I/O is non-blocking. This includes HTTP requests, database operations, and disk reads and writes, and single-threaded execution requires a callback function to be performed at run time, and then continue to do something else. When the operation is completed, the message is inserted into the queue with the provided callback function. At some point in the future, the message is removed from the queue and the callback function fires.

Although this interaction model may be familiar to developers who are accustomed to using the user interface, such as "MouseDown," and "click" events are triggered at some point. This is different from the synchronous request-response model that is typically performed on a server-side application.

Let's compare two small pieces of code, issue HTTP requests to www.google.com and output responses to the console. First look at Ruby and work with Faraday (a Ruby HTTP client development Library):

Response = Faraday.get ' http://www.google.com '
puts response puts '
done! '

The execution path is easy to track:

1, execute the Get method, the execution of the thread waits until the response is received
2, received from Google Response and returned to the caller, it is stored in a variable
3, the value of the variable (in this case, our response) is output to the console
4, the value "done!" Output to console
Let's use the Node.js and request libraries to do the same thing in javascript:

Request (' http://www.google.com ', function (error, response, body) {
 console.log (body);
});
 
Console.log (' done! ');

Slightly different on the surface, the actual behavior is different:

1. Execute the request function, pass an anonymous function as a callback, and execute the callback when the response is available sometime in the future.
2, "done!" Output to console now
3. At some point in the future, when responding to return and callback execution, output its contents to the console
Event Loops

Decoupling the caller and the response allows JavaScript to do something else while the runtime waits for the asynchronous operation to complete and the callback to trigger. But how do these callbacks are organized in memory and in what order? What caused them to be called?

The JavaScript runtime contains a message queue that stores a list of messages that need to be processed and the associated callback functions. These messages are in the form of queues in response to external events (such as mouse clicks or a response to an HTTP request) that are involved in the callback function. For example, if a user clicks a button but does not provide a callback function, then no message is added to the queue.

In a loop, the queue extracts the next message (each fetch is called a "tick"), and when the event occurs, the callback for the message executes.

Call of the callback function in the call stack as the initialization frame (fragment), because JavaScript is single-threaded, future message extraction and processing is stopped because all calls to the stack are returned. A subsequent (synchronous) function call adds a new call frame to the stack (for example, function init calls a function ChangeColor).

function init () {
 var link = document.getElementById ("foo");
 
 Link.addeventlistener ("click", Function ChangeColor () {
  This.style.color = "Burlywood";
 });
 
Init ();

In this example, when the user clicks the "foo" element, a message (and its callback function ChangeColor) is inserted into the queue and triggers the "onclick" event. When a message leaves the queue, its callback function ChangeColor is invoked. When ChangeColor returns (or throws an error), the event loop continues. As long as the function ChangeColor exists and is specified as a callback to the OnClick method of the "foo" element, clicking on the element causes more messages (and the associated callback ChangeColor) to be inserted into the queue.

Queue Append Message

If a function is invoked asynchronously in code (such as SetTimeout), the provided callback will eventually be executed as part of a different message queue, and it will occur on some future action of the event loop. For example:

function f () {
 console.log ("foo");
 SetTimeout (g, 0);
 Console.log ("Baz");
 h ();
}
 
function g () {
 console.log ("Bar");
}
 
function h () {
 console.log ("Blix");
}
 
f ();

Because of the non-blocking nature of the settimeout, its callback will be triggered at least 0 milliseconds later, rather than being processed as part of the message. In this example, settimeout is called, passing in a callback function g and delaying execution after 0 milliseconds. When we specify the time to arrive (the current situation is, almost immediately), a separate message will be added to the queue (g as the callback function). The result of the console printing is like this: "foo", "Baz", "Blix", and then the next action of the event loop: "Bar". If two calls are set to settimeout in the same call fragment-the values passed to the second argument are the same-their callbacks are inserted into the queue in the order in which they were called.

WEB workers

Using Web workers allows you to execute a time-consuming operation on a separate thread, freeing the main thread to do something else. A worker (worker thread) consists of a separate message queue, an event loop, and a memory space independent of the original thread that instantiates it. The communication between the worker and the main thread passes through the message, and looks much like the traditional event code example that we used to be familiar with.

First of all, our worker:

Our worker, which does some cpu-intensive operation
var reportresult = function (e) {
 pi = Somelib.computepitosp Ecifieddecimals (e.data);
 PostMessage (pi);
 
OnMessage = Reportresult;

The main block of code then exists in our HTML with the script-tag:

Our main code, in a <script>-tag with our HTML page
var piworker = new Worker ("Pi_calculator.js");
var logresult = function (e) {
 console.log ("PI:" + e.data);
};
 
Piworker.addeventlistener ("message", Logresult, false);
Piworker.postmessage (100000);

In this example, the main thread creates a worker and registers the Logresult callback function with its "message" event. In a worker, the Reportresult function registers itself with a "message" event. When the worker thread receives the message of the main thread, the worker queue a message with the Reportresult callback function. When the message is out, a new message is sent back to the main thread, and the new message is queued to the main thread (with the Logresult callback function). This enables developers to delegate CPU-intensive operations to a single thread, freeing the main thread to continue processing messages and events.

About closures.

JavaScript's support for closures allows you to register callback functions so that, when the callback function executes, it retains access to the environment they were created (even if the callback was executed to create a completely new call stack). It would be interesting to understand that our callback was executed as part of a different message rather than the one that created it. Take a look at the following example:

function changeheaderdeferred () {
 var header = document.getElementById ("header");
 
 settimeout (function Changeheader () {
  header.style.color = "Red";
 
  return false;
 };
 
 return false;
}
 
Changeheaderdeferred ();

In this example, the Changeheaderdeferred function is executed with the variable header. The function settimeout is invoked, causing the message (with the Changeheader callback) to be added to the message queue and executed after approximately 100 milliseconds. The changeheaderdeferred function then returns FALSE, ending the processing of the first message, but the header variable can still be referenced through the closure rather than being garbage collected. When the second message is processed (the Changeheader function), it retains access to the header variable declared in the scope of the external function. Once the second message (Changeheader function) finishes execution, the header variable can be garbage collected.

Remind

The JavaScript event-driven interaction model differs from many programmers ' custom request-response models, but as you can see, it's not complicated. Using simple message queues and event loops, JavaScript enables developers to use a large number of asynchronously-fired (asynchronous-triggered) callback functions while building their systems, allowing the RUN-TIME environment to handle concurrent operations while waiting for external events to trigger. However, this is only a method of concurrency.

The above is the entire content of this article, I hope to help you learn.

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.