Making JSONP Calls from HTML5 Web Workers

HTML5

HTML5 LogoThe importScripts() function can be used to load any JavaScript file asynchronously from within a Web Worker, making JSONP a snap.

I just put the finishing touches on a photo gallery for a fairly large commercial web site. This template involved two dependencies: mustache.js and a jQuery carousel plugin, as well as three JSONP calls. All of this has to happen before anything can be displayed in the browser. Fun stuff.

I’ve spent plenty of time pressing F5 over and over to see how many milliseconds I could shave off the page load time. Since there is a bit of data crunching that also has to happen once all dependencies and JSONP calls have loaded, I started to think that this project would be a perfect candidate for some Web Worker love (of course with a safety net for older browsers). After some A/B testing, I could see that there was no real savings when implementing Web Workers. This is because the average 3-second load time was mostly due to the multiple asynchronous calls, not the data crunching. Since asynchronous calls are asynchronous, they don’t lock-up the browser, and it is only their latency that “keeps us waiting.”

That said, in the process of setting up my A/B testing, I had fun messing with Web Workers, and picked up a few new tricks, so I thought I’d post an article about making JSONP calls from a Web Worker.

If you’re not too familiar with HTML5 Web Workers, you might want to read these three posts; they offer an overview and a quick dive in to the topic:

Getting Started with HTML5 Web Workers – Part I
Getting Started with HTML5 Web Workers – Part II
Getting Started with HTML5 Web Workers – Part III

Before diving into the Web Worker code, I’ll just mention that the JSONP call we make responds pretty quickly, almost too quickly. As a result, it’s tough to demo our Web Worker, because there is no sense of “wait” (I spent over an hour making a pretty “loading” experience that merely flickers for a nanosecond because the JSONP call returns so quickly : – ). So I’ve implemented a “sleep” feature: we add &sleep=NUMBER to the query string. This way, we can make the JSONP call perform a little slowly, which helps to demonstrate our topic. Here is the PHP code that is added to the top of the JSONP file:

Ok, a little JSONP / Web Worker Action Please!

Example # 1

In Example # 1, we have the code for our Web Worker. First, there is the JSONP callback. In this callback, we fire off a message to the script that started the worker, and pass it the JSON data. Note that we need to use JSON.stringify() to convert that JSON data to a string. This is because we can only pass strings as messages to and from a Web Worker. But if we “stringify” a JSON object, that will do just fine.

Next we have set up an event listener. When the calling script sends a message to this Worker, the code inside of the event listener is executed. We create a random integer which is used to tell the JSON page to “sleep” for a few seconds, imitating a slow response. The other random # is used as a cache buster.

After that, we simply make the JSONP call. The importScripts() is oh-so-lovely and makes it super easy to import any JavaScript file.

Example # 2

In Example # 2, we have a simplified version of the click handler for the “Make JSONP Call” button. It simply sends a message to the Worker, which “starts” it.

Example # 3

In Example # 3, we instantiate the Worker() constructor, and then set up the event listener for that Worker. The code inside of this event listener will be executed when the Worker sends this script a message. I won’t drive you nuts by going through it line-by-line, but on a high level, we take the JSON data that the Worker sends us, and use JSON.parse() to turn it back into an object. Then, leveraging Mustache.js, we create an unordered list, using the JSON data that the Worker fetched for us.

Here is a link to the full working example for this article. Make sure you click the “Make JSONP Call” button: http://examples.kevinchisholm.com/javascript/web-workers/jsonp/

Summary

Again, the very act of making an asynchronous script call is not so strenuous for the browser. But I can imagine a case in which you need to fetch some JSON and then crunch the return data before passing it to the calling script. In such a case, the “crunching” is what could bog down the browser. And since data you pass to a Web Worker is essentially “copied,” your script could wind up using more memory than necessary, by getting the JSON data, passing a copy of it to the Web Worker, and then getting a copy back from the Worker once it has finished doing some work on the data. That is three copies of the same chunk of data!

By initiating your JSONP call from the Web Worker, you get the data, crunch the data, and then pass the data to the calling script. This removes one “copy” from the whole scenario. And, I’m thinking that after sending the data from the Worker to the calling script, you could probably delete the data inside of the Worker, freeing-memory. Although it will probably get cleaned up by garbage collection. More fun stuff to investigate.

Happy Web Worker-ing!

Kevin

Helpful Links for Web Workers

http://www.sitepoint.com/javascript-threading-html5-web-workers/

http://www.storminthecastle.com/2013/04/19/make-your-ui-more-responsive-with-html5-web-workers/

http://www.codediesel.com/javascript/introducing-html5-web-workers/

http://refcardz.dzone.com/refcardz/html5-web-workers

http://www.tutorialspoint.com/html5/html5_web_workers.htm

Getting Started with HTML5 Web Workers – Part III

HTML5

HTML5 LogoBy instantiating the Worker() constructor twice, we can see how more than one number-crunching task can be passed off to separate threads, once again leaving the browser responsive and completely available to the user.

In Part II of this article, we discovered the liberating effect of implementing a single Web Worker. We were able to pass our number crunching work off to the Worker, which ran in a separate thread. As a result, the browser remained responsive (e.g. we were able to resize the box while the numbers were being crunched). In this third and final part of the article, we will take things one step further by spawning two number-crunching threads, all the while continuing to keep the browser completely responsive.

Part III: Multiple Web Workers

Example # 1

In Example # 1, we have for the most part, replicated the approach taken in Part II of this article. The only difference here is that we have created two instances of the Worker() constructor (myWorkerOne and myWorkerTwo). We are using the same physical worker file (i.e. worker.js), so the argument passed to the Worker() constructor is the same in both cases. From there the steps are the same. We create our event listeners, and from each “Crunch some numbers” button, a message is sent to the appropriate Worker instance.

Click here to see the full working demo for Part III of this article: http://examples.kevinchisholm.com/javascript/web-workers/basic/example-3.php

When you clicked both of the “Crunch some numbers” buttons, a separate number-crunching task was passed off to a Worker in a new thread. You can see that the Ajax loader gif spins with no problem, and you are able to resize the boxes as much as you wish.

Click here to compare the examples from all three of the parts of this article: http://examples.kevinchisholm.com/javascript/web-workers/basic/example-1.php?menu

Summary

In this article, we demonstrated how multiple Workers can be used simultaneously. Just as in the example from Part II of this article, we proved that while the Worker is crunching numbers, the browser is completely responsive and available to the user.

The examples in all three parts of this article were very simple and meant only to introduce the topic of Web Workers. There is a great deal more to talk about with regard to Web Workers and I do plan to do so here in this blog in the coming weeks.

More Helpful Links for Implementing HTML5 Web Workers

http://www.htmlgoodies.com/html5/tutorials/introducing-html-5-web-workers-bringing-multi-threading-to-javascript.html#fbid=CwNX9_fBBqp

http://html5demos.com/worker

http://caniuse.com/#feat=webworkers

Getting Started with HTML5 Web Workers – Part II

HTML5

HTML5 LogoImplementing an HTML5 Web Worker is all about instantiating the Worker() constructor, creating event listeners, and posting messages between the Worker and the script that started it.

In Part I of this article, we made the case for Web Workers. We discussed the oh-so nasty concept of locking up the browser and how the single-threaded nature of JavaScript ensures that long-running scripts will send visitors away none-to-pleased. In this second part, we will use a Web Worker to pass off our “crunch” function to a separate thread, keeping the browser responsive and completely available to the user.

Part II : A Simple Web Worker

Example # 1

In Example # 1, we instantiate the Worker() constructor, passing it the name of a JavaScrpt file that has already been created and which contains the web-worker code. This file must be on the same domain as the page that calls it. In our case, it is in the exact same folder as the web page, so the path to the file is simply the name of the file: “worker.js”.

After instantiating the Worker() constructor, we add an event listener. This allows the worker file that we specified (i.e. worker.js) to send a message to the script that started the worker. The anonymous function that is the second argument of the addEventListener() method takes an event object as an argument (in this example, we call it “e;” you can name it anything you like). In this anonymous function, we remove a CSS class from the target DOM element, and then fill that element with whatever message the worker sent us. That message is contained in the “data” property of the event object (i.e. “e.data”).

Application Web Root
The Web Root – Web Page and Separate WebWorker File

Example # 2

In Example # 2, we have an abbreviated version of the click event handler for the “Crunch some numbers” button. What I wanted to illustrate is that we “start” the worker by sending it a message.

Example # 3

In Example # 3, we have the code for our Web Worker (i.e. the file worker.js). While all of the code in the script is evaluated and executed when we instantiate the Worker() constructor (just like any JavaScript file), the code inside of the self.addEventListener() call only executes when the worker receives a message. In this example, we set the variable “msg” equal to the “crunch()” function. Our crunch() function takes anywhere between one and ten seconds to return, simulating that nasty number-crunching behavior we have been talking about.

When crunch() does finally return, we post a message back to the script that started the worker. In this case, the message is the return value of crunch(): a string of markup that says “I’m done…” and tells us how long it took.

Click here for the full working demo of Example # 2:  http://examples.kevinchisholm.com/javascript/web-workers/basic/example-2.php

When you clicked the “Crunch some numbers” button, you were still able to resize the box, or do anything else you wished. The number crunching work was passed off to our Web Worker, which ran in a separate thread, which left the browser completely responsive and available to you.

This is a major improvement over the example in Part I of this article! In Part III, we will expand this demo to include a second number-crunching task, illustrating how we can spawn not only one, but multiple tasks to other threads using Web Workers.

Summary

In this article, we were introduced to the workings of Web Workers. We learned how to instantiate a Web Worker, start the Worker, post a message to it, and create an event listener so that we can respond when the Web Worker sends us a message, and access that message. We also learned how to setup an event listener in the Worker file, and post messages back to the script that started the worker.

Helpful Links for Implementing HTML5 Web Workers

https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers

http://www.html5rocks.com/en/tutorials/workers/basics/

Getting Started with HTML5 Web Workers – Part I

HTML5

HTML5 LogoHTML5 Web Workers significantly minimize the limitations imposed by JavaScript’s single-threaded nature, allowing you to keep the browser responsive.

HTML5 Web Workers significantly minimize the limitations imposed by JavaScript’s single-threaded nature, allowing you to keep the browser responsive.
When folks express their excitement about HTML5, the discussion is usually focused around features such as the AUDIO / VIDEO tags, Geolocation, or maybe improved semantics. These are all super cool, as are many other features that are part of (or associated with) the HTML5 specification. But, it often amazes me how little attention is given to Web Workers. In my opinion, the addition of Web Workers is a big deal.

This article will be presented in three parts:

Part I : Making the Case for Web Workers
Part II: A Simple Web Worker
Part III: Multiple Web Workers

Part I : Making the Case for Web Workers

JavaScript is a single-threaded technology. Only one thing can be done at a time.
Period. This is fine at first, but when JavaScript is doing any heavy-lifting, it can lock up the browser. Locking up the browser is bad, very bad. This is like a waiter serving your food late, and then spilling it on you. Regardless of how apologetic the waiter may be, you are not likely to tell your friends how great that restaurant is. As a web developer, all you need to do is lock up the browser once and you can be sure that the user is never (ever) going to tell their friends anything good about the page they were just viewing (and by association, the whole site gets a bad rap). They will not “like” it, tweet it, “plus-one” it, “pin” it, “dig” it or…. ok, you get the point: Don’t lock up the browser.

Number-crunching is probably the most challenging context. While all modern browsers have made great strides with regard to the speed of their JavaScript engines, heavy-duty calculations can still take time.. sometimes a few seconds. Unfortunately, a few seconds is out of the question. Many consider 100 milliseconds to be the limit; i.e. if a synchronous piece of code needs more than 100 milliseconds to return then that code probably needs some more attention.

HTML5 Web Workers allow you to execute JavaScript in a different thread than the one that the browser is running in. This is a big win. It means that in certain cases, your multi-second number-crunching code can be handed off to a Web Worker, and the browser can remain happy, peppy and bursting with love.

Did you notice the words: “…in certain cases” ? There are some limitations to how you can use Web Workers. It is far from a free-for-all. For example, you cannot access the Window, Document or Parent objects. Heavy DOM manipulation is out. At first glance, this may seem like a drawback. But as you can imagine, providing access to the DOM from more than one thread immediately complicates things in a way that is not good.

The key to leveraging the power of Web Workers is hinted at by its very name “worker.” Think of this feature as a calculator (or many calculators), that can be sent off to do some “work”, and then report back when done. I won’t go too crazy on the details here, there are many web-based resources that can provide an in-depth view of Web Workers. I’ve listed a few at the end of this article.

To make the case for Web Workers, let’s consider the following code example:

Example # 1

In Example # 1, we have a function that essentially “sleeps” for five seconds. If you run this code in your JavaScript console, it will lock up the browser for five seconds. Nasty business. We will use this code extensively throughout Parts I, II and III of this article. Every time you see this function referenced, just imagine that it is crunching some numbers (i.e where you see “I’m only sleeping”). The key point here is that a function that would need a few seconds to do some resource-intensive work, would behave in exactly the same way: it would lock up the browser.

Example # 2

in Example # 2, we have expanded the crunch() function so that it “sleeps” for a random number amount of time, up to five seconds. This makes the function feel a bit more “real world” in that the amount of time the function takes to “crunch” will vary a bit.

Click here to see a full working example of our “crunch” function in action: http://examples.kevinchisholm.com/javascript/web-workers/basic/example-1.php

In the example page, when you clicked “Crunch some numbers”, the browser locked up. If you tried to resize the box by clicking the “Re-Size Box” button, not only did nothing happen, but you probably got the “wait” cursor (this behavior varies from browser to browser). I intentionally used an Ajax loader gif to illustrate this: the gif’s animation is frozen during the numbers crunching. Once the “crunch” function has completed, it updates us with a message which tells us how long it took, and the browser is responsive again.

This is the “waiter spilling food on you” scenario. And it is not good.

In Part II, we will dive into Web Workers and learn how that technology can help us to pass off our number crunching work to a different thread, and keep the browser responsive at all times.

Summary

In this article we introduced the concept of Web Workers. We discussed the single-threaded nature of JavaScript and how it poses a challenge when it comes to resource-intensive work. We made our case with an example of a simple function that will render the browser unresponsive.

Helpful Links for HTML5 Web Workers

http://www.w3.org/TR/2009/WD-workers-20091029/

http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html

http://en.wikipedia.org/wiki/Web_worker