In this article, you will develop a XUL application (XML User Interface Language). Familiarity with XUL development is certainly beneficial, but not strictly required. XUL is mostly an XML widget language, similar to HTML in some ways, with support for JavaScript and CSS. You can use other languages with XUL, but you will only use JavaScript in this article. Thus, experience with JavaScript is required, but knowledge of other languages is not needed. The concurrency APIs used in this article were introduced in Mozilla's JavaScript 1.9.1 that is part of Firefox 3.5. You can use either Firefox 3.5 or Mozilla's XULRunner 1.9.1 to run the code shown in this article. See Resources for links to these tools.
Back in 2005, Herb Sutter declared that the free lunch was over. His analysis and conclusion were both pretty simple. Moore's Law had run its course. Computers were no longer advancing through faster processors. Software developers had put this increasing processor speed to good use by always increasing the amount of computations needed! This was straightforward. Faster computers meant you could do more stuff. Now computers are getting faster by adding more cores. You can still do more stuff, but you have to do it using concurrent programming. You have to use those cores.
You have probably heard all of this before. Many programming languages and platforms have added new concurrency features to help developers take advantage of multi-core computers. For some languages that already had multi-threaded programming APIs, this meant creating better APIs and abstractions to make multi-threaded programming easier to understand and less error-prone. Some languages did not have any support for multithreaded programming and have added it. This is the case for JavaScript, the main programming language for XUL programmers. Starting with JavaScript 1.9.1, multithreaded programming has come to JavaScript on the XUL platform.
Now you might say to yourself: "Wait a minute! XUL is the main technology behind Firefox and its extensions. Don't try to tell me that these XUL applications have been single-threaded all of this time!" Of course you are correct. However, it is key to remember that XUL supports more than just JavaScript. Through the power of XPCOM, you can implement components in other languages, in particular in C++. Of course C++ has support for native threads, so that was always a way to use multithreading from within a XUL application. However, the native programming language for XUL has always been JavaScript, or more precisely, Mozilla's flavor of JavaScript. Until now, JavaScript lacked a way to explicitly spawn and manage arbitrary threads, but JavaScript 1.9.1 changes that. Despite being a minor release, JavaScript 1.9.1 adds a major new feature: multithreading through the Workers API.
So what exactly is this Workers API in JavaScript? With
Workers, you can spawn as many threads as you want, and you
can use those threads to do whatever tasks you want them to. In many scenarios, you might want to spawn one or more threads within your application. One common use case is to perform some periodic operation. This is common in many applications, and many developers use JavaScript's setInterval function for this. The only problem with this function is that when it periodically executes, it executes on the main thread and thus blocks any interactions from the user during that time. If its execution takes any noticeable time at all, then the application freezes up during this execution. Hence, the benefits of executing on a separate thread.
This really brings me to the more general use case for multiple threads: long running
operations. Any long running operation that operates on the main thread will cause an
application to freeze up. You always want such operations to execute on their own
thread. What are some examples of such long running operations? You might see examples
of prime factorizations of large integers, or sorting huge lists of complex data
structures, and those are certainly long running operations. They are not the most
common tasks to do in XUL applications. What is a little more common is some kind of
IO operation, like accessing a Web service, or reading from the local file system.
This is exactly the kind of operation you will examine in this article. You will see
that the Workers API allows you to not just spawn threads,
but to execute arbitrarily complex tasks on the spawned thread. Finally, you usually
want to perform some kind of update to your UI as a result of such operations, and
doing this from another thread can be very hazardous. Luckily, the Workers API was designed with this in mind, and greatly simplifies
what might be a difficult scenario. Look at how you can use the Workers API and examine it in the context of a simple application.
As mentioned earlier, one common use of multithreading is some type of IO
operation, such as accessing a Web service over the Internet. Now, JavaScript/XUL has
always provided multithreading for network operations: XMLHttpRequest. The secret sauce of Ajax defaults to performing the
network IO on a background thread with the caller providing a callback function that gets invoked on the main thread after the IO
completes. However, you do not have explicit control of this thread; the runtime does
it for you. Further, what if you need to do multiple network operations? In that case
your requests will get serialized by the runtime. In this application you will perform
this kind of task—accessing multiple remote Web services simultaneously using
the multiple threads through the Workers API. The
application will let users perform a "blind taste test" as they view and compare
anonymous results of these search engines: Google, Yahoo, and Microsoft's Bing.
Three search engines, three threads
The application that you will explore is pretty simple. It will allow the user to enter one or more search terms. It will then search the three search engines, and anonymously display the results so the user doesn't know which list of results came from which search engine. Start with the XUL code for the user interface (see Listing 1).
Listing 1. XUL UI code
<hbox>
<label value="Enter" id="lbl"/>
<textbox value="" id="term"/>
<button label="Go!" onclick="search()" id="btn"/>
</hbox>
|
This is simple XUL code to create a search form. It creates a horizontal layout with three widgets. The first widget is a label, the second is a text box where the user enters a search term, and the last widget is a button. When a user clicks the button, the search function is invoked. This is where the worker threads are spawned, as in Listing 2.
Listing 2. Spawning
Workers
function search(){
var keyword = document.getElementById("term").value;
var workerScripts = ["google.js", "yahoo.js", "bing.js"];
var worker = {};
for (var i=0;i<workerScripts.length;i++){
worker = new Worker(workerScripts[i]);
worker.onmessage = function(event) {
displayResults(event.data);
};
worker.postMessage(keyword);
}
}
|
If you used XUL based upon JavaScript before 1.9.1, then you have to queue up all three requests, or use XPCOM with C++ to retrieve the data efficiently. However, with JavaScript Workers, it becomes straightforward to spawn multiple threads to retrieve this data. Each Worker object takes a single string for its constructor. The string is the location of another JavaScript file that will become the body of the worker. The script in the worker's file will be executed on its own thread.
The three scripts in this question are titled google.js, yahoo.js, and bing.js. You put
those into an array and then iterate over the array. For each script in the array, you
create the Worker by simply passing in the string that
specifies the location of the worker's script. Next, for each worker being created,
you set its onmessage function. This is the function that
is called whenever the worker sends data back to the main thread. In this case you
simply delegate the work to another function called displayResults. Finally, to send the name of the search terms that
you want to use with each search engine, we call the postMessages function on each Worker object. This will allow the worker thread to access the Web service, thus all three Web services are called concurrently. Not only are the calls simultaneous, but the processing of the results is also done in parallel.
So what exactly goes on with this onmessage/postMessage
paradigm? This is the fundamental threading model behind the Workers API. The usual threading model that most people are familiar
with is the model used by C++, Java™ technology, and many other programming
languages. To communicate, threads generally modify shared memory. This is efficient,
but leads to a lot of complications (semaphores, mutexes, and so on). These complexities are needed for UI programming as well, since you can quickly cause your UI to lock up or crash if multiple threads alter the UI. Instead of bringing all of these complexities to XUL, the JavaScript Workers API uses a simpler model. This model is based on message passing, and is somewhat similar to the actor model used in Erlang and Scala.
Going back to Listing 2, the Worker
instance acts as a proxy to the spawned thread. To send the thread a message, the
postMessage method on the Worker
instance is invoked. Any object can be passed to this method. Of course the spawned
thread can pass a message back to its parent thread. When it does this, the onmessage method of the Worker instance is
invoked. This has a no-op default implementation, so you must override this (if you care about results coming back from the thread). In Listing 2, to override this, set it equal to a function that accepts a single parameter called event. This is the object that gets sent from the spawned thread. For the function in Listing 2, extract the data property of the event, as this is the actual data sent by the thread, and pass it to another function for updating the UI.
You have seen the parent thread's side of things. What about the spawned, child threads? As seen in Listing 2 above, a separate JavaScript file is used for each spawned thread. In Listing 3, look at the first of these for accessing the Google search API.
Listing 3. Google search worker
onmessage = function(event){
var keyword = event.data;
var results = searchGoogle(keyword);
postMessage(results);
}
function searchGoogle(keyword){
var url = "http://ajax.googleapis.com/ajax/services/"+
"search/web?v=1.0&rsz=large&q="+keyword;
var xhr = new XMLHttpRequest();
xhr.open("GET", this.url, false);
xhr.send();
var response = JSON.parse(xhr.responseText);
var results = [];
var result = {};
var data = response.results;
for (var i=0;i<data.length;i++){
result.url = data[i].url;
result.title = data[i].title;
result.description = data[i].content;
results.push(result);
}
return results;
}
|
The code in Listing 3 has some similarities to what you saw in Listing 2. The thread has an onmessage method.
This is the function that is invoked whenever a message is sent to the thread. If you go back to Listing 2, the postMessage method on the Worker instance is invoked. This causes the onmessage function in Listing 3 to be invoked. The object passed in to postMessage becomes the data property on the object passed to the onmessage method. This is the keyword being used for the search in this example.
Going back to Listing 3, once the keyword is extracted from the
message that was passed in, the searchGoogle function is
invoked. This function uses Google's search API to request search results for the
keyword. To invoke the Web service, notice that you use the standard JavaScript API
XMLHttpRequest. You might notice that when you send the
request, using the open method, you specify three
parameters. The last parameter specifies if the request is asynchronous or not. It
defaults to true, so the request is asynchronous. In such cases, you need to override
the onreadystatechange function of the XMLHttpRequest instance so that you can set a callback function for the asynchronous request. However, when you
make such a request from a Worker thread, you don't need to do this. Instead, set the asynchronous flag to false, and make the call synchronously. Thus the send method blocks until the response has been returned from the Web service. This allows you to easily handle the response.
In this case the response from Google is a JSON structure. You can eval the response directly, but it is safer to use a parser. The
standard JSON parser from json.org is included as part of JavaScript 1.9.1 as well. So
you can simply use its parse method to safely parse the JSON data into a JavaScript
object. The rest of the code simply extracts data from the structure returned by
Google and puts it into a common structure. This data is then sent back to the parent
thread by using the postMessage function. When the postMessage function on the worker thread is invoked, this will cause
the onmessage method on the Worker instance (in the parent thread) to be called with the data
sent from the worker thread. That is why you set this onmessage function back in Listing 2. Each of the other Workers does very similar work. For example, Listing 4 shows the worker thread for the Bing search engine.
Listing 4. Bing search worker
onmessage = function(event){
var keyword = event.data;
var results = searchBing(keyword);
postMessage(results);
}
function searchBing(keyword){
var bingAppId = "YOUR APP ID GOES HERE";
var url = "http://api.search.live.net/json.aspx?Appid="+
bingAppId+"&query="+keyword+"&sources=web";
var xhr = new XMLHttpRequest();
xhr.open("GET", this.url, false);
xhr.send();
var response = JSON.parse(xhr.responseText);
var results = [];
var results = {};
var data = response.SearchResponse.Web.Results;
for (var i=0;i<data.length;i++){
result.url = data[i].Url;
result.title = data[i].Title;
result.description = data[i].Description;
results.push(result);
}
return results;
}
|
As you can see, this is very similar to the code in Listing 3. It
uses the onmessage/postMessage paradigm to receive and send
data from its parent thread. The URL of the Web service is a little different, of
course. The return structure is also a little different, but you simply map it back to the common structure seen in Listing 3. As you can imagine, the code for the Yahoo Worker is very similar to the Google and Bing Workers. The URL is a little different, and the mapping back to the normalized data structure is a little different (see Download for all of the source code). Once the data is in a normalized structure, it can be passed to a common function for updating the user interface.
Concurrent programming promises to be the key to successful applications both today and
especially in the future. Applications that use multiple threads to get the most out
of their environment can provide a superior user experience. In this article, you took
a very simple example, querying three popular search engines. However, you can imagine
the improvement in user experience it makes to retrieve the results from each engine
simultaneously, instead of doing it one search engine at a time. Even on a single CPU
machine this will make a big difference, as you do not waste as much time waiting on a
response from a Web service. The Worker APIs added to
JavaScript 1.9.1 make this type of programming easy for any XUL-based application. You
can employ the techniques shown here in Firefox extensions or desktop applications
that use XULRunner. The APIs are simple to use, and you can spawn multiple threads
without worry about locking. The Workers API just removed
any excuse to not use multithreading to improve your XUL applications .
| Description | Name | Size | Download method |
|---|---|---|---|
| Search engine test source | xul-workers.zip | 3KB | HTTP |
Information about download methods
Learn
- An introduction to XML User Interface (XUL) development (Michael Galpin, developerWorks, November 2008): If you are just getting started with XUL, this is a good place to enhance your Web development skills and build a XUL-based blog editor. Learn about tools to help you develop desktop apps with XUL.
- Browser extensions using XUL (Uche Ogbuji, developerWorks, October 2007): Explore how useful concurrency is in Firefox extensions, and now it's easier than ever.
- Create Web applets with Mozilla and XML (Nigel McFarlane, developerWorks, October 2003): See how you can create enhanced Web pages with XUL.
- An introduction to XPCOM (Rick Parrish, developerWorks, February 2001): Learn all about XPCOM, which used to be the only way to multi-thread in XUL.
- The busy Java developer's guide to Scala: Explore Scala concurrency (Ted Neward, developerWorks, February 2009): In this introduction, meet the actor model used in Scala, which has many similarities to Workers in JavaScript.
- An Introduction to XUL Part 1: Take nice survey of XUL and how to make rich user interfaces with nothing more complicated than a text editor.
- Mozilla developer center: Visit the source for all things XUL for customized, feature-rich cross platform apps that can run on or off the Internet.
- The busy Java developer's guide to Scala: Functional programming for the object oriented (Ted Neward, developerWorks, January 2008): Learn how Scala gives you the best of both worlds with functional and object-oriented techniques. For a comprehensive tour of Scala, read the entire series.
- Scala and XML (Michael Galpin, developerWorks, April 2008): See how Scala makes many common programming tasks easier, including working with XML.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- developerWorks XML zone: Visit this compendium of articles and tutorials to help developers leverage the power of XML when crafting effective, efficient Web applications.
- XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- The technology bookstore: Browse for books on these and other technical topics.
- developerWorks
podcasts: Listen to interesting interviews and discussions for software developers.
Get products and technologies
- Firefox 3.5: Get this open source Web browser.
- Mozilla XULRunner 1.9.1: Download and use this Mozilla runtime package to bootstrap XUL+XPCOM apps that are as rich as Firefox and Thunderbird.
- IBM product evaluation versions: Download or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- XML zone discussion forums: Participate in any of several XML-related discussions.
- developerWorks blogs: Check out these blogs and get involved in the developerWorks community.

Michael Galpin is an architect at eBay. He is a frequent contributor to developerWorks and has also written for TheServerSide.com and the Java Developer's Journal, as well as his own blog. He has been programming professionally since 1998 and holds a degree in mathematics from the California Institute of Technology.
Comments (Undergoing maintenance)





