Implementation of multiple JavaScript threads

Source: Internet
Author: User

Note: The following content is based on the GIF onload event in IE, so all tests are ie only
Images to be used

Let's look at a simple fact:

CopyCode The Code is as follows: <script language = "JavaScript">
VaR IMG = new image ();
IMG. src = "attachment/1178365293_0.gif ";
IMG. onload = function ()
{
Alert ("to disable it, press and hold the ESC key and click the close button ");
}
</SCRIPT>

If not expected, a large number of alert Prompt Windows should pop up for your IE. Note: "a lot "!

The reason is simple: IE repeatedly executes the onload event for multiple frames of GIF images. That is, each time an animation is played, the onload event is re-executed.

(Note: pressing ESC will stop GIF animation playing, so the onload event will also be stopped)

With this feature, we can simulate the implementation of multiple threads:
See the following code:

Copy code The Code is as follows: image a onload execution times: <span id = "threada"> 0 </span> <br>
Image B onload execution times: <span id = "threadb"> 0 </span> <br>
Image C onload execution times: <span id = "threadc"> 0 </span>
<SCRIPT>
Function IMG (threadid, Src)
{
VaR IMG = new image;
IMG. onload = function ()
{
VaR c = parseint (document. getelementbyid (threadid). innerhtml );
Document. getelementbyid (threadid). innerhtml = isnan (c )? 1: ++ C;
}
IMG. src = SRC;
Return IMG;
}

VaR imga = new IMG ("threada", "attachment/1178365293_0.gif ");
VaR imgb = new IMG ("threadb", "attachment/1178365293_1.gif ");
VaR imgc = new IMG ("threadc", "attachment/1178365293_2.gif ");
</SCRIPT>

Is that a bit interesting?
Let's look at the following code:

Copy code The Code is as follows: <SCRIPT>
// By rimifon
VaR threads = new array;
Onload = function ()
{
For (VAR c = 1; C <501; C ++)
{
Threads. Push (New thread (c ));
}
}
Function go (sender)
{
VaR isstart = sender. value = "start all ";
For (var x in threads)
{
Threads [X]. Start = isstart;
}
Sender. value = "all" + (isstart? "Pause": "Start ");
}
Function thread (ID)
{
This. Start = 0;
VaR cursor = this;
VaR span = Document. createelement ("span ");
VaR counter = Document. createtextnode ("0 ");
Span. appendchild (Counter );
VaR DIV = Document. createelement ("Div ");
Div. appendchild (document. createtextnode ("Thread" + ID + ":"));
Div. style. cursor = "Pointer ";
Div. onclick = function ()
{
Cursor. Start =! Cursor. Start;
}
Div. oncontextmenu = function ()
{
IMG. onload = NULL;
This. removenode (true );
Return false;
}
Div. appendchild (SPAN );
Document. Body. appendchild (DIV );
VaR IMG = new image;
IMG. onload = function ()
{
If (cursor. Start) counter. Data = parseint (counter. Data) + 1;
Div. style. backgroundcolor = cursor. Start? "# Abcdef": "yellow ";
}
IMG. src = "images/51js.gif ";
}
</SCRIPT>
<Input type = button value = "start all" onclick = "Go (this)">
<Input type = button value = "pop-up dialog box" onclick = "alert ('Dialog test')">

Some code is derived from rimifon. (Reproduced in http://Dnew.cn)
Introduction to JavaScript multi-thread programming
Although more and more websites are developing with Ajax technology, building a complex Ajax application is still a challenge. What are the main causes of these difficulties? Is it about asynchronous communication with the server? Or GuiProgramWhat about design problems? These two tasks are usually completed by the desktop program. Why is it so difficult to develop an Ajax application that can implement the same function?

Difficulties in Ajax Development
Let's use a simple example to understand this problem. Suppose you want to build a tree-structured announcement board system (BBS), which can interact with the server according to user requests, dynamically load each articleArticleInstead of loading all the article information from the server at one time. Each article has four attributes: The system can be used as a unique ID, post name, article content, and an array containing all its sub-article IDs. Assume that a function named getarticle () can load the information of an article. The parameter received by this function is the ID of the document to be loaded. You can obtain the document information from the server. The returned object contains four attributes related to the document: ID, name, content, and children. The routine is as follows:

Copy codeThe Code is as follows: function (ID ){
VaR A = getarticle (ID );
Document. writeln (A. Name + "" + A. content );
}

However, you may notice that repeatedly calling this function with the same article Id requires repeated and useless communication with the server. To solve this problem, you can use the getarticlewithcache () function, which is equivalent to a getarticle () with caching capability (). In this example, the data returned by getarticle () is saved as a global variable:Copy codeCode: var cache = {};
Function getarticlewithcache (ID ){
If (! Cache [ID]) {
Cache [ID] = getarticle (ID );
}
Return cache [ID];
}

Now we have cached the read articles. Let's take another look at the function backgroundload (), which applies the cache mechanism we mentioned above to load all the article information. Its purpose is to pre-load all its sub-articles from the background when reading an article. Because the data in the article is tree-structured, it is easy to write a recursiveAlgorithmTo traverse the tree and load all the articles:Copy codeThe Code is as follows: function backgroundload (IDS ){
For (VAR I = 0; I <IDs. length; I ++ ){
VaR A = getarticlewithcache (IDs [I]);
Backgroundload (A. Children );
}
}

The backgroundload () function receives an ID array as a parameter, and then calls the previously defined getarticldwithcache () method through each ID to cache the article corresponding to each ID. Then, the backgroundload () method is recursively called through the subarticle ID array of the loaded article, so that the entire article tree is cached.

So far, everything seems perfect. However, as long as you have experience developing Ajax applications, you should know that this naive implementation method will not succeed at all. The basis of this example is that getarticle () uses synchronous communication by default. However, as a basic principle, JavaScript requires asynchronous communication when interacting with the server because it is single-threaded. For simplicity, putting everything (including GUI events and rendering) in one thread is a good program model, this eliminates the need to consider the complex issues of thread synchronization. On the other hand, he also exposed a serious problem in application development. The single-threaded environment seems to respond quickly to user requests, but when the thread is busy processing other things (such as calling getarticle ()), you cannot respond to users' mouse clicks or keyboard operations.

What will happen if synchronous communication is performed in this single-threaded environment? Synchronous communication interrupts the execution of the browser until the communication result is obtained. While waiting for the communication result, the thread stops responding to the user and remains locked until the call is returned. For this reason, when the browser is waiting for the server response, it cannot respond to user behavior, so it looks like frozen. When getarticlewithcache () and backgroundload () are executed, they are all based on the getarticle () function. Since downloading all articles may take a considerable period of time, for the backgroundload () function, the freezing of browsers in this period of time is a very serious problem-since all browsers have been frozen, it is impossible for users to execute background pre-loading data first when they are reading articles, in this case, the current article cannot be read.

As mentioned above, since synchronous communication may cause such a serious problem, JavaScript regards asynchronous communication as a basic principle. Therefore, we can rewrite the above program based on asynchronous communication. Javascript requires writing asynchronous communication programs in an event-driven programming method. In many cases, you must specify a callback program. Once a communication response is received, this function will be called. For example, the getarticlewithcache () defined above can be written as follows:Copy codeCode: var cache = {};
Function getarticlewithcache (ID, callback ){
If (! Cache [ID]) {
Callback (Cache [ID]);
} Else {
Getarticle (ID, function (){
Cache [ID] =;
Callback ();
});
}
}

This program also calls the getarticle () function internally. However, it should be noted that the getarticle () function designed for Asynchronous Communication receives a function as the second parameter. When you call this getarticle () function, you must send a request to the server as before. The difference is that the function will return quickly instead of waiting for the response from the server. This means that when the execution right is handed back to the calling program, no response is received from the server. In this way, the thread can execute other tasks until it obtains the server response and calls the callback function at this time. Once the server responds, the second parameter of getarticle () will be called as a pre-defined callback function, and the return value of the server will be its parameter. Similarly, getarticlewithcache () must be modified to define a callback parameter as its second parameter. This callback function will be called in the callback function passed to getarticle (), so it can be executed after the server communication ends.

You may think the above changes are quite complicated, but the changes to the backgroundload () function will be more complicated. It will also be rewritten into a form that can handle callback functions:Copy codeThe Code is as follows: function backgroundload (IDs, callback ){
VaR I = 0;
Function L (){
If (I <IDs. Length ){
Getarticlewithcache (IDs [I ++], function (){
Backgroundload (A. Children, L );
});
} Else {
Callback ();
}
}
L ();
}

The modified backgroundload () function seems to be far from the previous one, but the functions they implement are not the same. This means that both functions accept the ID array as the parameter. For each element in the array, call getarticlewithcache (), and then apply the obtained sub-article ID to call backgroundload () recursively (). But it is also a loop access to the array, and the new function is not very recognizable. In the past, the program was completed with a for loop statement. Why are the two functions that implement the same function so different?

This difference stems from the fact that any function must return immediately after it needs to communicate with the server, such as getarticlewithcache (). Unless the original function is not executed, the callback functions that should receive the server response cannot be called. For JavaScript, it is impossible to interrupt the program during the loop process and execute the program from this breakpoint later, for example, a for statement. Therefore, in this example, the callback function is passed recursively to implement the loop structure instead of a traditional loop statement. For those familiar with the continuous transmission style (CPS), this is a manual Implementation of CPs, because loop syntax cannot be used, so even simple programs, as mentioned above, have to be very complex. The problem related to event-driven programming is the control flow problem: loops and other control flow expressions may be difficult to understand.

There is another problem: If you convert a function without asynchronous communication into a function using asynchronous communication, a callback function will be required as a new parameter for the rewritten function, this has caused a lot of problems for existing APIs, because internal changes do not limit the impact to the internal, but lead to overall chaotic changes of APIs and other API users.

What are the root causes of these problems? Yes, it is the Javascript single-threaded mechanism that causes these problems. Executing asynchronous communication in a single thread requires an event Driver Design and complex statements. If there is another thread that can process user requests while the program is waiting for the response from the server, the above complex technology is not needed.

Try multi-thread programming
Let me introduce concurrent. thread. It is a library that allows JavaScript to be programmed with multiple threads. Using it can greatly ease the difficulties mentioned above in Ajax development related to asynchronous communication. This is a free software library written in Javascript, provided that it complies with the Mozilla Public License and GNU General Public License protocols. You can download from their websiteSource code.

Download and use the source code immediately! Assume that you have saved the downloaded source code to a folder named concurrent. thread. js. Before performing any operations, run the following program. This is a simple function implementation:Copy codeThe Code is as follows: <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>

Execute this program to display the numbers starting from 0 in sequence. They appear one by one. You can view them on the screen. Now let's take a closer look at the code. The while (1) condition is applied to create a loop that won't be aborted. Normally, A JavaScript program that keeps using one thread and is the only thread will cause the browser to look like frozen, and naturally it will not allow you to scroll the screen. So why does the above program allow you to do this? The key lies in the concurrent. thread. Create () statement above while (1). This is a method provided by this library, which can create a new thread. The function passed in as a parameter is executed in this new thread. Let's fine tune the program as follows:Copy codeThe Code is 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 );
</SCRIPT>

In this program, a new function f () can repeatedly display numbers, which is defined at the beginning of the program segment. Then, the F () parameter is used to call the CREATE () method twice, the second parameter passed to the CREATE () method will be passed to F () without modification (). Execute this program, first you will see some decimal places starting from 0, followed by some large numbers starting from 100,000, and then followed by the first decimal order number. You can observe that the program is alternately displaying decimals and large numbers, which means that the two threads are running at the same time.

Let me demonstrate another usage of concurrent. thread. The preceding example calls the CREATE () method to create a new thread. This can also be achieved without calling any APIs in the library. For example, the previous example can be written as follows:Copy codeThe Code is as follows: <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> ";
}
</SCRIPT>

In the script tag, it is easy to write an infinite loop with JavaScript. You should note the type attribute in the tag, which is a strange value (text/X-script. multithreaded-js). If this attribute is placed in the script tag, then concurrent. thread will execute the program between labels in a new thread. You should remember that, in this example, the concurrent. Thread library must be included.

With concurrent. thread, it is possible to switch the execution environment between threads freely, even if your program is very long and has a strong continuity. We can briefly discuss how to perform this operation. In short, code conversion is required. Roughly speaking, first convert the function passed to create () into a string, and then rewrite it until it can be executed in batches. Then these programs can be executed gradually according to the scheduler. The scheduler is responsible for coordinating multithreading. In other words, it can make adjustments as appropriate so that every modified function can run at the same opportunity. Concurrent. Thread does not actually create a new thread. It only simulates a multi-threaded environment based on the original single thread.

although the converted functions seem to run in different threads, only one thread is actually doing this. Executing synchronous communication in the converted function will still cause browser freezing. You may think that the previous problems have not been solved. However, you don't have to worry about it. Concurrent. Thread provides a custom communication library that uses JavaScript asynchronous communication methods. It is designed to allow other threads to run when a thread is waiting for the response from the server. The communication stock is under concurrent. thread. HTTP. Its usage is as follows: copy Code the code is as follows:

The get () method, as its name implies, can get the content of the specified URL through the http get method, it takes the target URL as the first parameter, use an array representing the HTTP Request Header as the second optional parameter. The get () method interacts with the server. When the server responds, an XMLHTTPRequest object is returned as the return value. 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, you don't have to worry about freezing the browser when the program waits for the response from the server. In addition, there is a post () method that can be used to send data to the server:Copy codeThe Code is as follows: <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 uses 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 the third optional parameter.

If you use this communication library to implement the getarticle () method in the first example, you will soon be able to write getarticlewithcache () and backgroundload () using the simple method in the example at the beginning of the article () and other functions that call the getarticle () method. Even if the version of backgroundload () is reading article data, as shown in the following example, another thread can respond to user requests, so the browser will not be frozen. Now, how practical is multithreading used in JavaScript?

Want to know more
I introduced you to a library that can apply multithreading in javascript: Concurrent. thread. The content of this article is only basic. If you want to learn more, I recommend that you go to the tutorial. It provides more information about concurrent. Thread usage and lists documents available for advanced users. Visiting their website is also good, where more information is provided.

Related author
Daisuke Maki: after graduating from the Natural Science Division of the liberal arts college of International Christian University (obtained a bachelor's degree in literature), he also obtained a master's degree in information at the Graduate School of o-communications. Good at Ajax for web development and JavaScript Application. He developed concurrent. thread. This design was applied to the project explatory software project guided by the Information Technology Promotion Agency (IPA) in Japan for the financial year 2006.

At present, he has a master's degree in engineering and is registering for a doctorate at the Graduate School at the University of Momo-communications.

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.