See two articles about the JS thread

Source: Internet
Author: User
Tags script tag setinterval

JavaScript's settimeout and setinterval are two very easy ways to deceive others, because we start to think that the call will be executed in a given way, and I think a lot of people have the same feeling, for example

[JavaScript] view Plaincopyprint?

  1. SetTimeout ( function () {alert (' Hello! ');}, 0);
  2. SetInterval (callbackfunction, 100);

It is thought that the greeting method in settimeout will be executed immediately, because it is not a thin air, but rather the JavaScript API document explicitly defines how many milliseconds the second parameter is meant to be, and the callback method is executed. This is set to 0 milliseconds, which is taken for granted immediately.
In the same way, the Callbackfunction method of setinterval is executed every 100 milliseconds at once.

But as JavaScript application development experience continues to grow and enrich, one day you discover a strange piece of code and think about it:

[JavaScript] view Plaincopyprint?

  1. Div.onclick = function () {
  2. SetTimeout ( function () {document.getElementById (' Inputfield '). focus ();}, 0);
  3. };

Since it is executed in 0 milliseconds, then what is still done with settimeout, at this moment, the firm faith has begun to waver.

Until the end of the day, you accidentally wrote a bad code:

[JavaScript] view Plaincopyprint?

  1. SetTimeout ( function () { while (true) {}}, 100);
  2. SetTimeout ( function () {alert (' Hello! ');}, 200);
  3. SetInterval (callbackfunction, 200);


The first line of code goes into the dead loop, but soon you'll find that the second, the third line is not the expected thing, the alert greeting does not appear, Callbackfunction also heard!

It's hard to accept that you're completely lost, because it's painful to change the long-established perception of the process of accepting new ideas, but the truth is that the quest for JavaScript truth doesn't stop because of pain, Let's expand the JavaScript thread and timer Discovery tour!

Remove the clouds and see the Moon Ming

One of the main reasons for all of the above myths is that the JavaScript engine has multiple threads executing, and the JavaScript timer callback function executes asynchronously.

In fact, JavaScript uses a decoy, and in most cases it deceives our eyes, where the backlight clarifies the fact that:

JavaScript engines are single-threaded, and browsers run JavaScript programs at all times and only one thread.

It makes sense to use a single-threaded JavaScript engine, and a single thread does not have to worry about threads synchronizing these complex problems, which are simplified.

So how does a single-threaded JavaScript engine work with the browser kernel to handle these timers and respond to browser events?
The following is a simple description of the browser kernel processing method.

The browser kernel implementation allows multiple threads to execute asynchronously, and these threads mate with each other in the kernel to maintain synchronization. If the implementation of a browser kernel has at least three resident threads: JavaScript engine thread, interface rendering thread, browser event trigger thread, and some other threads that are terminated after execution , such as HTTP request threads, which produce different asynchronous events, the following diagram illustrates how the single-threaded JavaScript engine interacts with other threads. Although each browser core implementation is different in detail, the invocation principle is similar.

As can be seen from the diagram, the JavaScript engine in the browser is event-driven, where events can be seen as a variety of tasks that the browser assigns to it, which can originate from the code blocks that the JavaScript engine is currently executing, such as calling settimeout to add a task, It can also be from other threads of the browser kernel, such as interface element mouse Click event, timing trigger time arrival notification, asynchronous request status change notification, etc. from a code perspective, the task entity is a variety of callback functions, and the JavaScript engine waits for tasks in the task queue to arrive. Because of single-threaded relationships, These tasks have to be queued, one after the other by the engine.

T1-t2. TN represents a different point in time, and the corresponding small square below the TN represents the task at that point in time, assuming the T1 moment, the engine runs in the T1 corresponding task block code, and at this point in time, we describe the state of the other threads in the browser kernel.

T1 moment:

GUI Render Thread:

The thread is responsible for rendering the browser interface HTML element, which executes when the interface needs to be redrawn (Repaint) or when a return (reflow) occurs because of an operation. This paper focuses on the JavaScript timing mechanism, but it is necessary to say the rendering thread, Because this thread is mutually exclusive to the JavaScript engine thread, it is easy to understand that because JavaScript scripts are manipulated DOM elements and render the interface while modifying these element properties, the element data obtained before and after the render thread may be inconsistent.

During the scripting run by the JavaScript engine, the browser render thread is in a suspended state, which means it is "frozen".

As a result, updates to the interface, such as adding nodes, deleting nodes, or changing the appearance of nodes, are not immediately reflected in the script, which is saved in a queue and is only available for rendering when the JavaScript engine is idle.

GUI Event Trigger Thread:

The execution of JavaScript scripts does not affect the triggering of HTML element events, in the T1 time period, the first is the user clicked a mouse button, click the browser event triggered by the thread capture after a mouse click event, by the figure, for the JavaScript engine thread said, This event is transmitted asynchronously to the end of the task queue by another thread, and the mouse click event is waiting to be processed because the engine is working on the T1 task.

Timed Trigger Thread:

Note that the browser model timer counters here are not counted by the JavaScript engine, because the JavaScript engine is single-threaded and if it is not counted when it is in a blocked thread state, it must rely on the outside to timing and trigger the timing, so the timed events in the queue are also asynchronous events.

From the figure, in this T1 time period, after the mouse click event triggered, the previously set of settimeout timed also arrived, at the moment for the JavaScript engine, the timed trigger thread produced an asynchronous timed event and placed in the task queue, the event is queued to the Click event Callback, Wait for processing.
In the same vein, or in the T1 time period, the next setinterval timer was added, due to the interval timing, in the T1 segment is triggered two times, the two events are queued to the end of the queue for processing.

As can be seen, if the time period T1 very long, much larger than the timing interval of setinterval, then the timed trigger thread will continuously generate asynchronous timed events and put to the end of the task queue, regardless of whether they have been processed, but once the T1 and the first scheduled event before the task has been processed, The timed events in these permutations are executed sequentially, because, for the JavaScript engine, each task in the processing queue is handled the same way, only in a different order.

After T1, that is, the currently processed task is returned, the JavaScript engine checks the task queue, finds that the current queue is non-empty, takes out the corresponding task execution under T2, and so on, and so on, it looks like this:

If the queue is not empty, the engine takes a task out of the queue header until the task finishes processing, returning the engine to run the next task, and other tasks in the queue that are not returned by the task cannot be executed.

I believe you are now well aware that JavaScript is multi-threaded and understand how JavaScript timer works, let's take a look at some of these cases:

Case 1:settimeout and SetInterval

[JavaScript]View Plaincopyprint?
    1. SetTimeout (function () {
    2. / * code block ... * /
    3. SetTimeout (Arguments.callee, 10);
    4. }, 10);
    5. SetInterval (function () {
    6. / * code block ... * /
    7. }, 10);



These two pieces of code see the same effect, in fact, the first paragraph in the callback function settimeout is the JavaScript engine to set a new settimeout timing, assuming that the last callback processing until the next callback to start processing as a time interval, Theory two settimeout callback execution interval >=10ms. The second paragraph since the setinterval set timing, the timed trigger thread will continuously generate asynchronous timed events every 10 seconds and put them at the end of the task queue. Theoretically two setinterval callback execution interval <=10.

Case 2:ajax is the asynchronous request really asynchronous?

Many classmates friends do not know, since said JavaScript is single-threaded run, then XMLHttpRequest after the connection is really asynchronous?
The request is actually asynchronous, but the request is made by the browser to open a new thread request (see), when the state of the request changes, if the callback was previously set, this asynchronous thread will produce a state change event in the JavaScript engine processing queue to wait for processing, when the task is processed, The JavaScript engine is always a single-threaded run callback function, or a single-threaded run of the function set by onreadystatechange.


bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbb

While more and more websites are being developed using AJAX technology, building a complex AJAX application is still a challenge. What is the main cause of these difficulties? is an asynchronous communication problem with the server? Or the GUI programming problem? Usually these two tasks are done by a desktop program, so why is it so difficult to develop an AJAX application that can do the same thing?

The challenges of AJAX development

Let's take a simple example to understand the problem. Suppose you want to create a tree-structured bulletin board system (BBS) that dynamically loads information about each article, instead of loading all the article information from the server at once, based on user requests to interact with the server. Each article has four related attributes: An ID that can be uniquely identified in the system, the name of the sender, the content of the article, and an array of information that contains all of its child article IDs. First assume that there is a function named Getarticle () that can load an article information. The parameter that the function receives is the ID of the article to load, through which you can get the article information from the server. The object it returns contains four properties related to the article: Id,name,content and children. The routines are as follows:

function (ID) {
var a = getArticle (ID);
Document.writeln (A.name + "
"+ a.content);

You may notice, however, that this function is called repeatedly with the same Article ID and requires repeated and unhelpful communication with the server. To solve this problem, consider using the function Getarticlewithcache (), which is equivalent to a getarticle () with a cache capability. In this example, the data returned by GetArticle () is only saved as a global variable:

var cache = {};
function Getarticlewithcache (ID) {
if (!cache[id]) {
Cache[id] = getArticle (ID);
}
return Cache[id];

Now that you have cached the read-in article, let's consider the function backgroundload (), which loads all the article information using the caching mechanism we mentioned above. Its purpose is to pre-load all of its sub-articles from the background when the reader is reading an article. Because the article data is tree structured, it is easy to write a recursive algorithm to traverse the tree and load all the articles:

function Backgroundload (IDS) {
for (var i=0; i < ids.length; i++) {
var a = Getarticlewithcache (Ids[i]);
Backgroundload (A.children);
}

The Backgroundload () function receives an array of IDs as parameters, and then invokes the previously defined Getarticldwithcache () method with each ID, thus caching the article corresponding to each ID. The Backgroundload () method is then recursively called through the child article ID array of the loaded article, so that the entire article tree is cached.

Related Vendor Content

The ultimate hybrid-from Ali "Go Ah" architecture evolution look at the integration of web and native Nirvana new-android QQ Music architecture Evolution driving data visualization mobile development Platform and tool application in DT era how to catalyze a large agile organization?

Related Sponsors

Global Software Development Conference, April 23-25th, Beijing, please look forward to!

So far, everything seems to be perfect. However, as long as you have experience in developing AJAX applications, you should be aware that this naïve implementation is not successful at all, and this example is based on the default getArticle () using synchronous communication. However, as a basic principle, JavaScript requires asynchronous communication when interacting with the server because it is single-threaded. In terms of simplicity, it is a good program model to put everything (including GUI events and rendering) in one thread, because it eliminates the complexity of thread synchronization. On the other hand, he also exposes a serious problem in application development, where a single-threaded environment appears to respond quickly to user requests, but when the thread is busy with other things (such as calling Getarticle ()), it cannot respond to the user's mouse clicks and keyboard actions.

What happens if I do synchronous communication in this single-threaded environment? Synchronous communication interrupts the execution of the browser until the communication results are obtained. In the process of waiting for the result of the communication, the thread stops responding to the user and remains locked until the call returns because the server's call is not completed. For this reason, when the browser waits for the server to respond, it cannot respond to user behavior, so it looks like it is frozen. The same problem occurs when executing Getarticlewithcache () and backgroundload () because they are all based on the getarticle () function. Since downloading all the articles can take a considerable amount of time, for the Backgroundload () function, the browser freezes during this time is a very serious problem-since the browser has been frozen, when the user is reading the article, it is impossible to first to perform background preloading data, If you do this, you won't be able to read the current article.

As mentioned above, since synchronous communication can cause such serious problems in use, JavaScript uses asynchronous communication as a basic principle. Therefore, we can rewrite the above program based on asynchronous communication. JavaScript requires an event-driven programming approach to write asynchronous communication programs. In many cases, you must specify a callback program that will be called once the communication response is received. For example, the Getarticlewithcache () defined above can be written like this:

var cache = {};
function Getarticlewithcache (ID, callback) {
if (!cache[id]) {
Callback (Cache[id]);
} else {
GetArticle (ID, function (a) {
Cache[id] = A;
Callback (a);
});
}

The program also calls the Getarticle () function internally. It should be noted, however, that this version of the Getarticle () function designed for asynchronous communication receives a function as the second parameter. When this getarticle () function is called, it is the same as before to send a request to the server, the difference is that the function will now return quickly rather than wait for the response of the server. This means that when execution is handed back to the caller, there is no response from the server. As a result, the thread can perform other tasks until the server responds, and the callback function is called at this point. Once the server responds, the second parameter of GetArticle () is called as a pre-defined callback function, and the return value of the server is its parameter. Similarly, Getarticlewithcache () has to make some changes, defining a callback parameter as its second argument. This callback function is called in the callback function passed to Getarticle (), so it can be executed at the end of the server communication.

You may already think that the above changes are quite complex, but the changes to the Backgroundload () function will be more complex and should be rewritten to handle the callback function:

function Backgroundload (IDs, callback) {
var i = 0;
function L () {
if (I < ids.length) {
Getarticlewithcache (ids[i++], function (a) {
Backgroundload (A.children, L);
});
} else {
Callback ();
}
}
L ();

The modified backgroundload () function seems to be far from the one we used to be, but the functions they have implemented are not the same. This means that both functions accept an array of IDs as arguments, call Getarticlewithcache () for each element in the array, and then apply a recursive call to Backgroundload () that has obtained the child article ID. But the same is the circular access of the array, the new function is not very well recognized, the previous program is a For loop statement completed. Why are the two sets of functions that implement the same function so different?

The difference stems from the fact that any function must return immediately after encountering the need to communicate with the server, such as Getarticlewithcache (). Unless the original function is not in execution, the callback function that should accept the server response cannot be called. For JavaScript, it is not possible to break a program during a loop and continue executing a program from that breakpoint at a later time, such as a for statement. Therefore, this example uses recursive pass-through callback function to implement loop structure instead of a traditional loop statement. For those who are familiar with continuous delivery style (CPS), this is a manual implementation of CPS, because it is not possible to use the cyclic syntax, so even a simple procedure such as the one mentioned above is very complex. The problem with event-driven programming is control-flow problems: loops and other control-flow expressions can be difficult to understand.

Here's another question: if you convert a function that does not apply asynchronous communication to a function that uses asynchronous communication, then the overridden function will need a callback function as a new parameter, which poses a big problem for existing APIs because the internal changes do not confine the influence to the internal, It is a change of APIs that lead to overall confusion and other users of the API.

What is the root cause of these problems? Yes, it is the JavaScript single-threaded mechanism that causes these problems. Executing asynchronous communication in a single thread requires event-driven programming and complex statements. If a program waits for a response from the server, there is another thread that can handle the user's request, which is not required for this complex technique.

Try multithreaded Programming

Let me introduce concurrent.thread, a library that allows JavaScript to be multithreaded, and it can be used to greatly alleviate the difficulties associated with asynchronous communication in AJAX development as mentioned above. This is a free software library written in JavaScript, and it is subject to the two Protocols of Mozilla Public License and the GNU General Public License. You can download the source code from their website.

Download and use the source code now! Assuming that you have saved the downloaded source to a folder named Concurrent.Thread.js, run the following program before any operation, which is a very simple feature implementation:

<script type="text/javascript" src="Concurrent.Thread.js"></script>
<script type="text/javascript">
Concurrent.Thread.create(function(){
var i = 0;
while ( 1 ) {
document.body.innerHTML += i++ + "<br>";
}
});
</script>

The execution of this program will show the numbers starting from 0 sequentially, they appear one after another, you can scroll to see it. Now let's take a closer look at the code, and he's using the while (1) condition to create a loop that doesn't stop, and typically, a JavaScript program that constantly uses one and only one thread will cause the browser to look like it freezes, and it will not allow you to roll the screen. So why does the program above allow you to do this? The key is that the Concurrent.Thread.create () statement above the while (1), which is a method provided by this library, can create a new thread. The function passed as a parameter is executed in this new thread, so let's fine-tune the program as follows:

<script type="text/javascript" src="Concurrent.Thread.js"></script>
<script type="text/javascript">
function f ( i ){
while ( 1 ) {
document.body.innerHTML += i++ + "<br>";
}
}
Concurrent.Thread.create(f, 0);
Concurrent.Thread.create(f, 100000);

In this program there is a new function f () can repeat the number, it is defined in the beginning of the program section, and then the F () for the parameter call two times the Create () method, the second parameter passed to the Create () method will be passed to F () without modification. To execute this program, you will see some decimal numbers starting with 0, followed by a number of large numbers starting from 100,000, followed by a decimal order. You can observe that the program is alternately displaying decimals and large numbers, which means that two threads are running at the same time.

Let me show you another use of concurrent.thread. The example above calls the Create () method to make a new thread. It is also possible to do this without invoking any APIs in the library. For example, the previous example could be written like this:

<script type="text/javascript" src="Concurrent.Thread.js"></script>
<script type="text/x-script.multithreaded-js">
var i = 1;
while ( 1 ) {
document.body.innerHTML += i++ + "<br>";
}

Within the script tag, it's easy to write an infinite loop with JavaScript. You should notice the type attribute inside the tag, there is a very strange value (text/x-script.multithreaded-js), if this attribute is placed inside the script tag, Then Concurrent.thread will execute the program between the tags within a new thread. You should keep in mind that, as in this example, the Concurrent.thread library must be included.

With Concurrent.thread, it's possible to switch between the execution environment threads, even if your program is long and consistent. We can briefly discuss how to perform this operation. In short, code conversions are required. Roughly speaking, you first convert the function passed to create () to a string, and then rewrite it until it can be executed in batches. These programs can then be progressively executed in accordance with the scheduler. The scheduler is responsible for coordinating multi-threading, in other words, it can make adjustments at the appropriate time so that every modified function gets the same chance to run. Concurrent.thread actually did not create a new thread, only simulating a multithreaded environment on the basis of the original single thread.

Although the converted function appears to be running in a different thread, there is actually only one thread doing all of this. Performing synchronous communication within the converted function will still cause the browser to freeze, and you may think that the previous problems have not been solved at all. But you don't have to worry, Concurrent.thread provides a custom communication library that is implemented using JavaScript asynchronous communication, which is designed to allow other threads to run when a thread waits for a response from the server. This communication is in stock under Concurrent.Thread.Http. Its usage is as follows:

<script type="text/javascript" src="Concurrent.Thread.js"></script>
<script type="text/x-script.multithreaded-js">
var req = Concurrent.Thread.Http.get(url, ["Accept", "*"]);
if (req.status == 200) {
alert(req.responseText);
} else {
alert(req.statusText);
}

The Get () method, as its name implies, can get the contents of the specified URL through the Get method of HTTP, which takes the destination URL as the first parameter and an array representing the HTTP request header as an optional second parameter. The Get () method interacts with the server and returns a XMLHttpRequest object as the return value when the response from the server is obtained. When the Get () method returns, the server response has been received, so there is no need to use the callback function to receive the result. Naturally, there is no need to worry about when the program waits for the server to respond when the browser freezes. In addition, there is a post () method that can be used to send data to the server:

<script type="text/javascript" src="Concurrent.Thread.js"></script>
<script type="text/x-script.multithreaded-js">
var req = Concurrent.Thread.Http.post(url, "key1=val1&key2=val2");
alert(req.statusText);
</script>

The post () method takes the destination URL as the first parameter, and the content to be sent as the second parameter. Like the Get () method, you can also use the request header as an optional third parameter.

If you use this communication library to implement the Getarticle () method in the first example, you will soon be able to apply the simple method of writing Getarticlewithcache (), Backgroundload () in the beginning of the article. and other functions that call the Getarticle () method. Even if that version of Backgroundload () is reading the article data, as usual there is another thread that can respond to user requests and therefore the browser will not freeze. Now, can you understand how useful it is to apply multithreading in JavaScript?

Want to know more

I've introduced you to a library that you can apply multithreading to in JavaScript: Concurrent.thread. The content of this article is only a very elementary thing, if you want to know more in-depth, I recommend you to see the tutorial. It provides more content about concurrent.thread usage, and lists the documents that are available to advanced users, and is the most suitable material for getting started. It's also good to visit their website, where more information is available.

See two articles about the JS thread

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.