Home >Web Front-end >JS Tutorial >Implementation method of JavaScript multi-threading_javascript skills

Implementation method of JavaScript multi-threading_javascript skills

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOriginal
2016-05-16 19:13:421260browse

Note: The following content is based on the onload event of GIF in IE, so all tests of IE only
need to use a few pictures

Let’s first look at a simple fact:

Copy code The code is as follows:




As expected, your IE should pop up a lot of alert prompt windows. Note that it is "a lot"!

The reason is very simple: IE repeatedly executes the onload event of multi-frame GIF, that is, every time the animation is played, the onload event is re-executed.

(Note: Pressing the ESC key will stop the playback of the gif animation, so it will also stop the execution of the onload event)

Using this feature, we can simulate the implementation of multi-threading:
See The code below:

Copy code The code is as follows:

Number of image A onload executions :0

Number of image B onload executions: 0

Image C onload execution times: 0
<script> <br>function Img(threadID,src) <br>{ <br>var img = new Image; <br>img.onload = function() <br>{ <br>var c = parseInt(document.getElementById(threadID).innerHTML); <br>document.getElementById(threadID).innerHTML=isNaN(c) ?1: c; <br>} <br>img.src = src; <br>return img; <br>} <br><br>var imgA = new Img("ThreadA","attachment/1178365293_0.gif "); <br>var imgB = new Img("ThreadB","attachment/1178365293_1.gif"); <br>var imgC = new Img("ThreadC","attachment/1178365293_2.gif"); <br> </script>


Isn’t it interesting?
Look at the following code again:

Copy the code The code is as follows:

<script> <br>//by Rimifon <br>var Threads = new Array; <br>onload = function() <br>{ <br>for(var C=1;C<501;C ) <br>{ <br>Threads.push(new Thread(C)); <br>} <br>} <br>function Go(sender) <br>{ <br>var IsStart = sender.value=="Start all "; <br>for(var x in Threads) <br>{ <br>Threads[x].Start = IsStart; <br>} <br>sender.value = "All" (IsStart?"Pause":" Start"); <br>} <br>function Thread(ID) <br>{ <br>this.Start = 0; <br>var cursor = this; <br>var span = document.createElement("span" ); <br>var counter = document.createTextNode("0"); <br>span.appendChild(counter); <br>var div = document.createElement("div"); <br>div.appendChild(document .createTextNode("Thread" ID ":")); <br>div.style.cursor = "pointer"; <br>div.onclick = function() <br>{ <br>cursor.Start = !cursor. Start; <br>} <br>div.oncontextmenu = function() <br>{ <br>img.onload = null; <br>this.removeNode(true); <br>return false; <br>} <br>div.appendChild(span); <br>document.body.appendChild(div); <br>var img = new Image; <br>img.onload = function() <br>{ <br>if(cursor .Start) counter.data = parseInt(counter.data) 1; <br>div.style.backgroundColor = cursor.Start?"#abcdef":"yellow"; <br>} <br>img.src = "images /51js.gif"; <br>} <br></script>



Part of the code is quoted from Rimifon. (Reprinted from http://Dnew.cn)
Introduction to JavaScript multi-threaded programming
Although more and more websites are developing using AJAX technology, building a complex AJAX application is still is a difficult problem. What are the main reasons for these difficulties? Is it an asynchronous communication issue with the server? Or is it a GUI programming issue? Usually these two tasks are completed by desktop programs, so why is it so difficult to develop an AJAX application that can achieve the same function?

Difficulties in AJAX development
Let us understand this problem through a simple example. Suppose you want to build a tree-structured bulletin board system (BBS), which can interact with the server according to user requests and dynamically load the information of each article, instead of loading all article information from the server at once. Each article has four related attributes: an ID that can be used as a unique identifier in the system, the name of the poster, the content of the article, and an array information containing the IDs of all its sub-articles. First, assume that there is a function named getArticle() that can load an article information. The parameter received by this function is the ID of the article to be loaded, through which the article information can be obtained from the server. The object it returns contains four attributes related to the article: id, name, content and children. The routine is as follows:


Copy code The code is as follows:

function ( id ) {
var a = getArticle(id);
document.writeln(a.name "" a.content);
}

However, you may notice , calling this function repeatedly with the same article ID requires repeated and unhelpful communication with the server. To solve this problem, you can consider using the function getArticleWithCache(), which is equivalent to getArticle() with caching capabilities. In this example, the data returned by getArticle() is only saved as a global variable:
Copy code The code is as follows:

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

Now that the read article has been cached, let us consider the function backgroundLoad() again, which uses what we mentioned above The caching mechanism loads all article information. Its purpose is to preload all its sub-articles from the background when a reader reads an article. Because the article data is structured in a tree, it is easy to write a recursive algorithm to traverse the tree and load all articles:
Copy code The 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, thus caching the articles corresponding to each ID. Then the backgroundLoad() method is recursively called through the sub-article ID array of the loaded article, so that the entire article tree is cached.

So far everything seems to be looking 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 for 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. In terms of simplicity, putting everything (including GUI events and rendering) in a thread is a good programming model, because then there is no 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()), it cannot respond to the user's mouse. Responds to clicks and 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 results of the communication are obtained. While waiting for the communication result, because the server call has not yet completed, the thread will stop responding to the user and remain locked until the call returns. Because of this, the browser cannot respond to user actions while it waits for a response from the server, so it appears to freeze. The same problem will occur when executing getArticleWithCache() and backgroundLoad(), because they are both based on the getArticle() function. Since downloading all articles may take a considerable period of time, the freezing of the browser during this period is a serious problem for the backgroundLoad() function - since the browser has frozen, when the user is When reading an article, it is impossible to perform background preloading data first. If you do this, you will not even be able to read the current article.

As mentioned above, since synchronous communication can cause such serious problems in use, JavaScript regards 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 routine that will be called once a communication response is received. For example, the getArticleWithCache() defined above can be written like this:
Copy code The code is as follows:

var cache = {};
function getArticleWithCache (id, callback) {
if ( !cache[id] ) {
callback(cache[id]);
} else {
getArticle (id, function( a ){
cache[id] = a;
callback(a);
});
}
}

this The program also calls the getArticle() function internally. However, it should be noted that this version of the getArticle() function designed for asynchronous communication accepts a function as the second parameter. When calling the getArticle() function, a request is sent to the server as before. The difference is that now the function will return quickly instead of waiting for a response from the server. This means that when execution is returned to the calling program, there is no response from the server. In this way, the thread can perform other tasks until it gets a response from the server, and call the callback function at this time. Once the server responds, the second parameter of getArticle() is called as a predefined callback function, and the server's return value is its parameter. Similarly, getArticleWithCache () also needs to make some changes and 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 is completed.

You may already think that the above changes are quite complicated, but the changes to the backgroundLoad() function will be more complicated, and it will also need to be rewritten into a form that can handle callback functions:
Copy code The code is as follows:

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 looks very different from our previous function, but the functions they implement are the same. This means that both functions accept an ID array as a parameter, call getArticleWithCache() for each element in the array, and then recursively call backgroundLoad () with the sub-article ID obtained. However, the same cyclic access to the array is difficult to identify in the new function. In the previous program, it was completed with a for loop statement. Why are the two sets of functions that implement the same function so different?

This difference stems from the fact that any function must return immediately after encountering a situation where it needs to communicate with the server, such as getArticleWithCache(). The callback function that should receive the server response cannot be called unless the original function is not executing. With JavaScript, it is not possible to interrupt a program during a loop and resume execution later from this breakpoint, such as with a for statement. Therefore, this example uses recursive delivery of the callback function to implement a loop structure instead of a traditional loop statement. For those familiar with Continuous Transfer Style (CPS), this is a manual implementation of CPS. Because loop syntax cannot be used, even a simple program such as the aforementioned tree traversal has to be written very complicated. A problem associated with event-driven program design is that of control flow: loops and other control flow expressions can be difficult to understand.

There is another problem here: if you convert a function that does not apply asynchronous communication to a function that uses asynchronous communication, then the rewritten function will require a callback function as a new parameter, which is already Existing APIs pose a big problem because internal changes do not limit the impact internally, but lead to overall confusion of the APIs and other users of the API.

What is the root cause of these problems? Yes, it is JavaScript's single-threaded mechanism that causes these problems. Performing asynchronous communication in a single thread requires event-driven programming and complex statements. If there is another thread that can handle user requests while the program is waiting for a response from the server, then the above complex techniques are not needed.

Try multi-threaded programming
Let me introduce Concurrent.Thread, which is a library that allows JavaScript to perform multi-threaded programming. Applying it can greatly alleviate the problems mentioned above in AJAX development. Difficulties related to asynchronous communication. This is a free software library written in JavaScript. The premise of using it is to comply with the 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! Assume that you have saved the downloaded source code to a folder named Concurrent.Thread.js. Before performing any operation, run the following program. This is a very simple function implementation:
Copy code The code is as follows:



Executing this program will sequentially Displays numbers starting from 0, they appear one after another, and you can scroll to see it. Now let's take a closer look at the code. It uses a while(1) condition to create a loop that will never terminate. Normally, a JavaScript program that continuously uses one and only thread like this will cause the browser to appear to freeze. If it’s the same, naturally you won’t be allowed to scroll. So why does the program above allow you to do this? The key is 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 us fine-tune the program as follows:
Copy the code The code is as follows :




In this program there is a new function f() that can display numbers repeatedly. It is defined at the beginning of the program segment. Then the create() method is called twice with f() as the parameter and passed to create() The second parameter of the method will be passed to f() unchanged. When you execute this program, you will first see some decimals starting from 0, then some large numbers starting from 100,000, and then the numbers following the previous decimal order. You can observe that the program alternately displays decimals and large numbers, which indicates that two threads are running at the same time.

Let me show you another use of Concurrent.Thread. The above example calls the create() method to create a new thread. It is possible to achieve this without calling any APIs in the library. For example, the previous example can be written like this:
Copy the code The code is as follows:




in script Within the tag, an infinite loop is simply written in JavaScript. You should notice the type attribute in the tag. There is a very unfamiliar value (text/x-script.multithreaded-js). If this attribute is placed in the script tag, then Concurrent.Thread will be in a new thread. Execute the program between tags within. You should remember that, as in this case, 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 long and has strong continuity. We can briefly discuss how to do this. In short, a code switch is needed. Roughly speaking, the function passed to create() is first converted into a string, and then rewritten until it can be executed in batches. These programs can then be executed step by step according to the scheduler. The scheduler is responsible for coordinating multiple threads, in other words, it can make adjustments when appropriate so that every modified function gets an equal chance to run. Concurrent.Thread does not actually create a new thread, it just simulates a multi-threaded environment based on the original single-thread.

Although the converted functions appear to be running in different threads, 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 might 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 implemented using JavaScript's asynchronous communication method. It is designed to allow other threads to run while one thread is waiting for a response from the server. This communication library 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 be obtained through the HTTP GET method Specifies the content of the URL, which takes the target URL as the first parameter and an array representing the HTTP request headers as the optional second parameter. The get() method interacts with the server and returns an XMLHttpRequest object as the return value after getting the response from the server. 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 no longer have to worry about the browser freezing while the program is waiting for a response from the server. In addition, there is a post() method that can be used to send data to the server:
Copy code The code is as follows:



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 pass the request header as an optional third parameter.

If you use this communication library to implement the getArticle() method in the first example, then you will soon be able to write getArticleWithCache(), backgroundLoad () using the simple method in the example at the beginning of the article And other functions that call the getArticle() method. Even if that version of backgroundLoad() is reading article data, there is still another thread that can respond to user requests, so the browser will not freeze. Now, can you understand how useful multi-threading is in JavaScript?

Want to know more
I introduce you to a library that can apply multi-threading in JavaScript: Concurrent.Thread. The content of this article is only very basic. If you want to know more in-depth, I recommend you to read the tutorial. It provides more information on the usage of Concurrent.Thread and lists documentation for advanced users, making it the best material to get started. It’s also a good idea to visit their website, which provides more information.

About the author
Daisuke Maki: After graduating from the Natural Sciences Branch of the College of Liberal Arts of International Christian University (with a Bachelor of Arts degree), he studied for a master's degree in Information at the Graduate School of Electro-Communications University. Specializes in web development and applying AJAX to JavaScript. He developed Concurrent.Thread. This design was applied in the Explatory Software Project, a project directed by the Japan Information Technology Promotion Agency (IPA) in fiscal year 2006.

Currently, he has a master's degree in engineering and is currently enrolled in the Graduate School of Electro-Communications University to pursue a doctoral degree.
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn