Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Tuesday, 31 December 2013

Book Review - Secrets of a JavaScript Ninja

I was watching a talk given by Angelina Fabbro on YouTube named "JavaScript masterclass". Its all about trying to become an expert in a particular field. It's a great talk and I suggest you give it a watch. In that talk, she mentions a book, "Secrets of a JavaScript Ninja" and being what I'd consider as an intermediate JavaScript developer myself, I thought it deserved a look. 

Just to give you an idea of the level of my JavaScript expertise, I've never been "taught" JavaScript, I've never attended any courses, I didn't cover it at University. My general method has been to look up pieces of code online as and when I've needed it. After doing this for a while you get a general feel of the language and after 10 odd years (on and off), I feel that I'm pretty knowledgeable in the area however, due to this learning methodology, undoubtedly there's going to be gaps in my knowledge and so I bought this book in hope to fill those gaps.

I'm very happy to report that it does fill in those gaps and more! It does so in a clear and concise way. Any new concept is backed up with code that's been written in such a way that its easy to follow and if there is a difficult concept, virtually all of the code has been broken down into small snippets so you can quickly stick it into JSFiddle and have a play around.

The book covers the core JavaScript language from topics ranging from the importance of functions (and they're far more powerful than I ever imagined) to regular expressions, runtime code evaluation and with statements. These are all areas that you can get by with not knowing in detail but when you do, you'll realize there are far simpler ways of doing the things you've been doing for the past 10 years. As frustrating that is, it is enlightening.

It also covers some of the problematic areas of programming in the browser and the cross browser problems that come hand in hand with this. From event handling, manipulating the DOM and CSS selectors, it covers them all and offers some inventive solutions to problems that you've probably come across yourself.

The really good thing about the book is that throughout it introduces you to patterns of programming JavaScript that you probably don't already use and really wish you did. If you're anything like me you'll find yourself thinking "I wish I had programmed x like this" or "I wish I knew about this feature before I programmed x, y, z".

The book is co-authored by John Resig, the creator of the most popular JavaScript library, jQuery and the book often uses methodologies and solutions that are used within that library. That to me, really gives this book substance, you're learning methods that are out there in the real world and that work so well that it's led to the immense popularity of jQuery.

If you're an intermediate JavaScript developer like me then this book is a must. Some of it you'll already know but some of it you won't and having that extra knowledge at your disposal will give you the tools to write far more elegant code.

If you're new to JavaScript development then I'd suggest holding off on this book for now. The book assumes a certain amount of knowledge regarding the language. You probably could work your way through the book and pick it up as you go along but it will take you a significant amount of time (ok, you'll be learning a good portion of a language so that's to be expected) but I think that process would take away something from the book so if you are in this category, I'd suggest going away, learning the basics and then picking this book up in a month or two's time.

Wednesday, 31 July 2013

JavaScript - Memory Leak Diagnostics

Memory leaks in JavaScript seem to be becoming an ever increasing problem. This is no surprise with JavaScript being used more and more but have you ever tried to solve a memory leak in JavaScript? It's no simple task, the tools simply don't exist to help determine what objects are leaking. You're essentially trying to find a needle in a haystack while blindfolded. Not Cool!

Until now.

There are three tools I would like to talk about. Sieve, Google Chrome's Heap Snapshot and the new boy on the block, Internet Explorer 11 Developer Tools.

In most cases, as a developer, you need a bit of a nudge in the right direction. Once you have an idea of where the problem may lie, we're pretty intelligent, we can usually work it out. Sieve gives you that nudge.
It's a memory leak detector for Internet Explorer. When running it'll show you all the DOM elements that are currently in memory. It'll then go one step further and it'll show you the DOM nodes that are currently leaking with an ID and everything. You can then use that information to try and find out why it's leaking. Usually it's because some piece of JavaScript some where references the element which has since been removed from the DOM.
sIEve - Memory Leak Detector

I must admit, I used this on a complex web application which had popup windows with iframes inside iframes and if it didn't crash then it did report some nodes were leaks when they weren't but, it did at least give me that nudge to look at a particular screen.

Chrome Heap Snapshot
Now we're talking! This is, to my knowledge, is the first proper way of determining what objects are specifically leaking. It allows you to take a snapshot of what objects are in memory at a given point in time and then you can compare these snapshots.

Chrome Heap Snapshot
This is rather handy. It means you can see which objects were created in the first snapshot and still exist in the second snapshot, i.e. the ones that are causing your problem!

The good thing about these snapshots is that it also tells you the "retaining tree". This is essentially the path from the root objects to the object in question, this means you can trace the path and work out why your object isn't being garbage collected.

The tool has a few other ways of helping you find your leak if comparing snapshots isn't quite cutting it. There is a "containment" view and a "dominator" view. I haven't had much use for the containment view (see here for more details) but the dominator view essentially lists the objects with the biggest memory consumption which can be helpful if you've got leaking global objects.

And a late entry.... Internet Explorer 11 Heap Snapshot
A developers preview has just been released on Windows 7 but so far so good. It's much the same as Chrome's version, if a little easier to read.

Internet Explorer 11 Developer Tools
There are two exceptions, firstly, on a positive note, it has a search functionality which Chrome doesn't have. This allows you to find objects that you know the id of. On a negative, it seems you can only compare sequential snapshots. You could not for example, compare your first and third snapshot which means you have to really think about when to take a snapshot.

I haven't had much time to really play around with this and it is only a developers preview but so far it looks like it could be a very useful tool. In actual fact, the whole new developer tools has a real potential but that's another blog post for another day.

For more info on the memory tab within the developer tools check out the MSDN documentation.

Conclusion...
As always, use the best tool for the job. For simple leaks, sieve is very good in finding the problem. For more complex problems the heap snapshots are the way to go.

The work Google and Microsoft have done in this area recently show how big JavaScript has now become and these tools are a great addition to any web developers tool kit.

If you do ever have to look for a memory leak, my thoughts are with you.

Good luck!

Saturday, 5 January 2013

League Predictor

For those of you that don't know, I play a fair amount of football and I run the website for the Sunday league team for which I play, Sumners Athletic. For many years I've used that site, and the server it's hosted on, to test new technologies and new methodologies and to improve my understanding of other web technologies.

Every now and again, when I'm playing around I create a control that I can share with the world. It's usually not the polished article but it does a job. Five or six years ago I created one of these controls. I created a "league predictor" in the form of a Java applet (who remembers those?).

What is a league predictor? Well, for a football team like mine that play in a league and each team plays each other twice (home and away), given all the results of the league to date, will work out the remaining fixtures. Those fixtures are then presented to the user so that they can make predictions about those games. At the end, the user hits a button and then re-draws the final league standing based on the predictions that the user has made.

Well, unless you've been out of the web application loop for the past 5 years, you'll probably know that Java applets are all but dead. JavaScript and HTML5 are the way forward so, I thought I'd re-write that original control using those technologies. The re-write is now done so I thought I'd make the code available to all. At some point I'd like to add animations to the league re-draw but that's another post for another day.

Anyway, the JavaScript file and corresponding CSS and HTML files can be found in this zip file.

If you want to see a working example, check this out: Sumners Athletic League Predictor
(Please ignore the fact that my team, Sumners Athletic, are currently bottom of the league!)


Just a few notes about the "control"...

Firstly, the JavaScript requires the initial data to be able to work out the league and what fixtures need to be played. To do this, it needs what I call, a results matrix in the form of a CSV file.

What's a results matrix? Well, it's essentially a grid of all the games played. You can imagine it as a grid, with the team names forming the first row and the first column. The results of each game (assuming you play home and away once) can then fit in the corresponding cells. If you open the CSV file included in the above zip file within a spreadsheet, you'll see what I mean.

This initial data is then requested by JavaScript and processed. It converts the CSV file into a 2D array and constructs team objects from that array. A team object consists of the name of the team, the amount of games played, won, drawn and lost. From this, a league can be constructed.

Then, from the results matrix, we can work out what fixtures are remaining. We can then display these fixtures to the user. Once they hit the "Predict" button, the predictions made are then fed back into the results matrix and the league is re-drawn based on the new results matrix.

And that's it.

Nothing too complex but I thought I'd share the code. I remember when I first started building my first football team website, I looked around for something that would do just this and couldn't find anything, now there's an option out there!



Saturday, 29 September 2012

Browser Compatibility and Window Management

With more and more users turning to Chrome, Safari and Firefox for their web browsing experience and with the explosion of mobile devices now connecting to the web, the importance of making your web application accessible across browsers has never been greater.

With this in mind, I started to look into exactly what's required to make a web application accessible on all web browsers. There's plenty of blog posts on just this issue but most of them deal with differences in layout engines. In this post, I want to talk about window management namely because different browsers handle this issue completely differently and it's caught me out.

window.focus()

If your application launches new windows, maybe to show a data entry screen then at some point, you're probably going to use window.focus() in order to bring the new window to the front.

In Internet Explorer, this isn't the problem. Take the following code as an example:


<html>
<head>
<title>Untitled</title>
<script language="JavaScript" type="text/javascript">
<!--
   function windowFocus(){
      var wnd = window.open('','','width=200,height=100')
 
      window.onfocus = function(){ wnd.focus(); };
   }
//-->
</script>
</head>
<body>

<a href="javascript: windowFocus();">Launch Window</a>

</body>

</html>


The above code is pretty simple. When you click on the link, a new window should open. Should you try and navigate back to the original window then the new window should re-focus and be put back on top.This can be a handy function, if you absolutely need your user to respond to an event in the popup window, then you can force them too (or the user closes the window, which is responding in a way...). 

The problem is this doesn't work in Chrome. And it's not a bug. It's by design. I should add it does work in Safari so it's not a WebKit issue. Essentially, Google argue that you, the developer, should not be able to play around with windows on the desktop. That's something that should only be performed by a user. Personally, I don't agree. To see the actual bug report, check here and here

If anyone does find a way of getting this to work on Chrome, then it'd be great to hear from you. I unfortunately wasn't able to find a way.

window.open() and resizable

As it goes, the application that I'm working on does open new windows. These windows act as data entry screens and all of these windows are set to be a specific width and height. The reason for this is that we use absolute positioning on all the form controls in order to display them on screen. If we let the browser set the size of the window then it's more than likely that it'll set the size to something that'll either be too small, so scroll bars will be needed to see all of the controls, or, the window will be too large and there will be massive amounts of blank space shown. So, we set the width and height specifically to avoid these issues and then we disable the users ability to re-size the window.

To do this, when we call window.open, we use specific features that set up the window as describe, specifically we set the width, height and set the resizeable attribute to false. (See W3Schools for the window.open definition).

Here is a good example:


window.open('http://www.google.com','','resizable=0,width=200,height=100');


Again, in Internet Explorer, this all behaves exactly as you'd expect. However, in Chrome, Safari and Firefox, we have a different story. And again, it's not a bug, it's by design.

In Chrome, Safari and Firefox it's impossible to make a window non-resizeable. There's no way round this, it's just not possible. The argument is that by making a window non-resizeable, it's possible that the developer has some how messed up their screen layout, making it impossible for the user to see things that aren't on the screen. If you make the screen resizeable then you avoid this possible complication and if everything does render correctly then the user just doesn't have to resize the window and then it's no skin off off of anyone's nose. So, these browsers just ignore the resizable attribute.

I can see where the browser vendors are coming from, their argument does make sense, but, I also think it looks unprofessional if the content of a screen doesn't resize accordingly with a window resize. This then means this functionality needs to be built in to the application to maintain a professional looking user interface.

For more on this issue, check out Firefox's bug report on it found here: https://bugzilla.mozilla.org/show_bug.cgi?id=177838

Window Height

As I said before, this web application opens up windows of a specific width and height. This is achieved by using the width and height attributes of the window.open e.g.


window.open('http://www.google.com','','width=1000,height=700');


In Internet Explorer, the window opens at the specified width and height. In Chrome and Firefox, the same is true but in Safari, it's a different story. For some unknown reason, when the window opens, it opens with a height of 780px. Odd. No other browser behaves like this.

If you try to use window.resizeTo to fix the size, e.g.


window.resizeTo(1000, 700);


Once this is run, the window changes to a height of 620px. So it still doesn't behave as it should. This only seems to occur on Safari 5.1 (I haven't tested on any earlier versions). After a bit of research, I found that this is a bug, check here for more info: https://discussions.apple.com/thread/3341535?start=0&tstart=0

I find it absolutely amazing that a browser that is so recognized and so widely used suffers from such a simple bug. Again, annoyingly, there's nothing we can really do to solve this. In theory, you could loop over different parameters to window.resizeTo until the window is set to the height you require but it's far from an ideal solution. Hopefully, Apple will address this issue shortly and this problem will go away. But I wouldn't like to put money on it.

Anyway, those are a few of the experiences I've had with window management for web applications across differing web browsers. If I come across any more then I'll be sure to post them.

Enjoy.

Wednesday, 1 August 2012

ExtJS - A Review


Around nine months ago, I was looking into a potential project for work. In it's simplest form, this project involved building a web application that would mostly be built using JavaScript and that worked on all the major browsers and in particular, it must be viewable on an iPad. So, I set about searching for a JavaScript framework that would support this.

Now I class myself as quite the geek and I like to think that I know of most of the major JavaScript frameworks. JQuery, Dojo, Prototype, etc. On top of that there's a few control libraries such as ComponentArt and Obout which I'm also quite familiar with. I looked into all of these but their functionality and look and feel didn't really jump out at me. I thought I'd do a bit of research and came across a framework that I'd never come across before... Sencha's ExtJS Framework. After spending the past couple of months working nearly exclusively with the framework, I thought it'd be a good idea to share my experience with you people so that if you're in a similar position to me, trying to decide whether or not to use an unfamiliar framework, you have a bit more extra information to go on.

It's worth mentioning that I'm in no way affiliated with Sencha so this is a completely independent review.

So, what do I look for in a good framework? Well, I think there's six categories to look at:
  1. Functionality - Unsurprisingly, a good framework needs to do what you need it to do. If it doesn't fit your requirements then there's no point in using it.
  2. Performance - There's not a whole lot of use in having a framework that does everything you need it to if it takes days to do it. How well does it perform?
  3. Ease of use - I would say I'm proficient in JavaScript. I'm certainly no expert. I expect a framework/library to be understandable and usable by someone with my level of understanding of the language. I do not want to have to take a two month extensive course in the inner workings of JavaScript in order to use the thing.
  4. Documentation - Any and every good framework/library needs to have good documentation. You don't want to be stepping through code to work out how to render something. It's much more effective to look up the documentation, have a quick read and then away you go.
  5. Extensibility - The chances are that at some point during your development cycle, you're going to need to add to the framework in order to achieve your desired functionality. How easy is this to do?
  6. Support - Sometimes you just can't work something out, is the support out there to help you through these difficult times?
So, how does the ExtJS framework compare in these categories?

Functionality

ExtJS has the most extensive functionality of any JavaScript framework I've ever come across. It has the ability to create some great user interfaces with some great special effects. Want pictures flying across the screen? No problem. Want something to fade in or out? Easy. And that's just for starters. It has a whole charting module: bar, line, graph, area, scatter, radar charts can all be created with minimal fuss. Along side that you've got grids which automatically support sorting, paging, editing and grouping.

Charts and graphs is only a small
piece of ExtJS functionality
ExtJS doesn't just do charting controls. It's has loads more to offer. Combo boxes which are a more enhanced version of the basic select HTML element are a selling point. There's also menu and toolbar controls which allow you to build user interfaces that will be familiar to your user. There are many more controls, just check out their examples here: http://www.sencha.com/products/extjs/examples/.

On top of all the controls, there's the functionality that the controls themselves bring to the table. Bar charts can just be rendered, or, you can animate them so they bounce in to position. Want to show a legend? No problem, that's in there too. Just about every time I've thought "I wonder if I can do x, y and z", I have a look and low and behold the framework supports it. It really is a very impressive framework.

Performance

With the amount of functionality that ExtJS does provide, performance is always going to be a talking point, especially when so much relies on manipulating the DOM which we all know can be slow. Now I've used ExtJS 4.0 extensively and I must say that the performance is very good. Like any programming library, there's way in which you can optimize your code so that you get the most out of it and I believe that if you do optimize then you'll be very impressed with its performance.

Performance of ExtJS4.0 is impressive!
There is a downside here though... ExtJS 4.1 was recently released and so I tried upgrading my project to use the new and "improved" library. After the upgrade, not only did certain controls just not work, the performance of my site seriously deteriorated. The whole reason for upgrading was to see if the new version improved performance, according to the promo by Sencha, it would do and although the 4.0 version wasn't exactly slow, if I could gain a bit more performance just by upgrading then it'd be stupid not too right? Well, I upgraded, spent a day fixing things that the new library broke and then spent another day optimizing the code and it was still slower than the 4.0 version. We're not talking about a few tenths of a second, we're talking  10's of seconds. At this point, I gave up and reverted back to the 4.0 version. Maybe it's possible to optimize it so it does run faster but with no real guarantee of that, I didn't feel I could justify spending the time in attempting it.

Ease of Use

ExtJS is exactly what I'd expect a good JavaScript framework to be in terms of ease of use. I simply picked it up and started to play around with it and soon got to grips with its functionality and how it can be used. Sencha provide loads of good examples ranging from the basic to the more advanced. All of their examples have their source code attached, you can simply look at the source code and work out what's going on. All of the objects and functions are logically named so the code is easy to follow. Put that together with a modern browsers JavaScript debugging capabilities and you can work out exactly how everything works and from there you can work out how to adjust the code to suit your needs.

If that isn't good enough, Sencha also provide well written tutorials on how to use the framework and how to deploy it, making it as simple as possible. If you want to check those out then have a look here.

Documentation
Documentation is a must for any framework
This is one area that ExtJS really does shine. The documentation for ExtJS really is excellent. Every method, property and configuration is well documented, just take a look here if you don't believe me. Not only do they provide documentation for the current version, they also have documentation for previous versions as well so you won't be looking at documentation that no longer applies!

You'd think this is one area that all frameworks would do well in, after all, documenting is just a case of writing down what everything does. You'd expect framework providers, especially ones that charge for use, would devote time to this area. However, you'll be surprised how poor the documentation is out there. jQuery is a framework that I've had a fair amount of experience with and they're pretty good with documentation, in contrast, I've also had a lot of experience with ComponentArt and they're documentation is absolutely shocking. I've wasted hours of my life trying to figure out how to use ComponentArt controls or trying to find out exactly what a certain property/method does because the documentation just simply doesn't tell you. Nine times out of ten, it's either non-existent or incomplete. You have no idea how much of a difference comprehensive documentation makes when you're trying to use a new framework.

Extensibility
Almost every time I've had to use a framework, it never quite works as I need it to so I end up modifying the source code or ideally, I build on top of the framework to add a bit of functionality to it. ExtJS recognises this and provide ways for you to override and extend objects. The framework heavily relies upon inheritance so extending and overriding controls is a very familiar concept for programmers that use object oriented concepts on a day to day basis.

Support
No matter how easy a framework is to use and no matter how good their documentation is I can guarantee at some point or the other you will come across a problem that you're struggling to solve. At this point you'll want to ask the wider world for a bit of help. Sencha have specific forums for this and for a fee you can access specific forums that are monitored by Sencha developers. ExtJS is fast becoming a widely used framework so, if you post a problem on a well known forum (say StackOverflow for example) then you'll be almost guaranteed a reply.

So... In Conclusion....

I think it's pretty fair to say that I'm a massive fan of the framework. This has blown frameworks that I have previously used out of the water. Some of the things I've managed to build in a day would have taken me months without the use of the framework. The documentation and general ease of use make developing applications with the framework a simple and effective task and because of the sheer quality of documentation, you feel your productivity increases just by using it. The thing I like the most... and this sounds kind of odd but, it just works. The quality of coding is very high. I've been using the framework on and off now for about nine months and I can count the number of problems I've come across on one hand and even then, I've been able to solve them with minimal effort.

It's not all good though, as I've stated previously, there is one big downside... upgrading and backwards compatibility. I upgraded from 4.0 to 4.1 and everything, and I do mean everything, broke. When I eventually got things working again the performance was so bad that I had to revert everything and stick with 4.0. I don't seem to be the only person that's had problems either. If you want to have a look for yourself, then you can check out the comments to Sencha's blog post about the 4.1 release here. Here's one comment that jumped out and me and summed up my frustration after a couple of days of trying to get things working after the upgrade:

"What a shocking release. An app that works without fault in 4.0.7 doesn't even show up properly in 4.1. We just got Sencha'd ... again!"

But that's the only fault I can find. If you're not worried about backwards compatibility and if the framework in its current state does what you need then I couldn't recommend it higher. It truly is a fantastic framework to work with. Just don't try upgrading.

Tuesday, 15 May 2012

IE, JavaScript and the Story of the Weeping Angels


I came across a very odd problem the other day in the way in which Internet Explorer handles DOM items with an ID.

Take the following piece of HTML for an example.


<html>
<head><title></title></head>
<body>
<div id="testElement" style="width: 100px; height: 100px; border: 1px solid black;"></div>
</body>
</html>


You can't get much simplier than that. Now say you want to access testElement and change the width of the element. You'd probably do that using the following piece of JavaScript code:


document.getElementById('testElement').style.width = '200px';


All very straightforward so far. There is another way of doing this though, one which isn't recommended but is supported by all the major browsers. You can simply write:


testElement.style.width = '200px';


If an element in your HTML has an ID, the browser will automatically put it in the window scope so you can access it directly. No need for document.getElementById. Cool eh?

Well, it turns out Internet Explorer supports this little feature in a bit of an odd way. Take the following HTML page:


<html>
<head><title></title>
<script language="JavaScript" type="text/javascript">
<!--
  TestObject = function() {
  this.id = 'TestObject';
  }
//-->
</script>
</head>
<body>
<div id="testElement"></div>
<script language="JavaScript" type="text/javascript">
// alert(testElement.id); // We'll uncomment this line a bit later.
window.testElement = new TestObject();
alert(testElement.id);
alert(window.testElement.id);
</script>
</body>
</html>


What you've done here is create a DOM element with an id of testElement. So, the browser should have created a window.testElement variable that'll give you the appropriate DOM element when accessed. You've then explitically defined the testElement variable to be a new TestObject. So in theory, when the first and second alert is shown, the testElement variable should be pointing at our TestObject. The id should therefore be 'TestObject'. In both alert boxes, 'TestObject' should be displayed.

When you run the above, that's exactly what happens. No big surprise there.

Ok, now uncomment the commented line. What I'd expect here is that the first box should display "testElement" as that's the id of the DOM element. You then assign the TestObject to testElement so, when the second and third alert box is shown, you'd expect to see "TestObject".

When you run the above, the first alert box displays 'testElement'. Good so far. The second alert box displays 'testElement'. Eh? That's surely wrong. The third alert box displays 'TestObject'. What? How can window.testElement and testElement be pointing at different things? They're the same variable! Comment the line again and everything goes back to normal. How can this be?!


Weeping Angels!

For you Doctor Who fans, you'll know what I'm talking about when I talk about Weeping Angels, but for those who have no idea, a weeping angel is a creature that, when looked at, automatically turns to stone. When not being viewed, they go about their usual business. It's a good analogy for this behaviour because, after a bit of experimenting, I found that as soon as you look at the testElement variable, it's at that point that the browser actually points the variable at the DOM element and makes it read only. This means that if you reference the variable anywhere, then it'll affect what your code is actually doing. Even if you're debugging and place a watch on the variable, it'll have the same effect. These kind of variables, in my book, are about as ugly as a weeping angel, just see the above picture for an example.

I should say, only Internet Explorer (I tested on IE9) seems to handle DOM variables like this. The above code behaves exactly as you'd expect in both Chrome and Firefox.

So, how to avoid this? As most JavaScript programmers know, programming in the global (window) scope is just bad practice, for a variety of reasons but the main one is doing so can lead to naming conflicts pretty easily, especially if you're using third party libraries. This problem re-affirms this. It is a naming conflict, just not in the traditional sense as the browser is doing some of the work for you. Anyway, if you avoid programming in global scope then you won't come across this problem. Unfortunately, from time to time, it's unavoidable, especially if the problem is actually caused by a third party library, like in my case. In these cases, as you saw before, if you reference the variable using window.variableName, then it seems that that will always point to your object, not the DOM item, which should hopefully give the behaviour that you want.

Enjoy!

Wednesday, 2 May 2012

HTML5 - Web Workers

It's been a while since my last blog but, here's the next chapter of my HTML5 overview, Web Workers.

So, what are Web Workers? Let's start off with some background information about JavaScript. JavaScript was originally developed by Netscape back in 1995. Its primary use was to allow developers to manipulate web pages, which, as you can imagine, were very basic back in 1995. In order to do this JavaScript was designed as a single-threaded language. Unlike its namesake Java (which is a completely unrelated language by the way) and many other languages, JavaScript does not support threads. The reason for this, I imagine, was very simple. How would you go about designing a multi-threaded language whose primary aim was to modify something (the Document Object Model (DOM)) that was shared between threads, without incurring deadlock problems? This problem remains unsolved. And so JavaScript runs on one single thread.

One Single Thread -  A one-trick pony?

Is it really a bad thing? I suppose it can be argued that in itself it's not. The design decision not to support threading in JavaScript was a good one. It makes it simpler to learn; it avoids some potentially horrific problems and; as the web has thrived in the past two decades, so has JavaScript. It can't be that bad right? Well, yes and no. When everything runs on one thread  it can lead to a very poor user experience. The User Interface (UI) can become non-responsive if not programmed correctly. In order to address this problem two functions were built into JavaScript: setTimeout and setInterval. These allow a piece of code to run after a pre-defined amount of time. The idea being that you could schedule long running code to run when the UI wasn't busy and the thread was free, essentially "hiding" the fact that JavaScript all runs on a single thread. These little hacks have allowed developers to get pretty inventive and have allowed JavaScript to flourish.

Ok, all is good then. What's the problem?

As I said, these are basically "hacks". What happens when the user starts clicking but you've already started to execute a long-running piece of code? You have a problem! The system will not be able to respond to the user's action until the code has completed its execution. And after all, some code, especially data centric code, just takes a long time to run. When this occurs, you'll see an error similar to this:


There's not a whole lot you can do about that. If you do have code that'll take a long time to run then you're a little stuck.

So, where do Web Workers come in?

Simple. Web workers bring multi-threading to JavaScript. They come with a few restrictions though and one is quite a biggy. Web workers cannot access the DOM. Allowing multiple threads access to a non-thread safe resource (the DOM) would cause all sorts of problems so the same design decision was made as in 1995. What they do allow you to do is to process and return data in a separate thread to the UI, so the time of seeing those pesky "unresponsive script" errors should now be gone forever!

Multi-threading eh? Woo! Where do I start?

Well, first you need to make sure you're using a web browser that actually supports web workers. To find that out you can simply visit caniuse.com and look it up. I should mention here that if you're using Chrome and the JavaScript file you're testing is stored locally and isn't running on a web server such as IIS, then you need to enable a flag on Chrome for everything to work. Simply start up Chrome with this command: chrome.exe --allow-file-access-from-files. This problem does not exist with Firefox. For more information, check out this Stack Overflow post.

Now that you are using a web worker enabled browser, you need to define your web worker. As the worker is in an entirely different thread, it has no access to loaded scripts, so you need to tell the worker which script to load. To do this we can use the following line:

var workerOne = new Worker('worker.js');


where worker.js is the name of your script.

Web workers communicate with the main UI thread in the form of messages. When a message is sent to a web worker, it causes the message event to fire within the thread. To hook in to this, your worker.js file needs to have the following content:


self.addEventListener('message', function(e) {
   var message = e.data;
  // Do something with the message
  self.postMessage(message.sort());
}, false);


To give you a quick overview of what's happening here, when the web worker is sent a message, the message event will be fired and the inner function defined above will run. It'll get the sent message by fetching it from the event object. Then, in a useful scenario some action would be performed based on that message. You'd then post a message back to the caller (usually the main UI thread). This could just be to notify the thread that it's completed or if you've done some data manipulation, you could post back the modified data. In the above example, the message is sorted and sent straight back.

So, that's the web worker defined. How do you now post messages to that worker thread so you can use it effectively? Well, you've defined your worker object earlier, you just need to:
a) Define what happens when the UI thread receives a message from the web worker and;
b) Send a message to the web worker which will start the whole process.

In much the same way that you need to hook into the message event within the web worker, you also need to hook into the message event on the web worker object itself, within the UI thread. Something like the following should do the job:


workerOne.addEventListener('message', function(e) {
        var numbersOne = e.data;         // Do something with this data
     }, false);


This will fire when a message is posted from the web worker to the UI thread. In the previous example, e.data will now contain your sorted data!

Ok, now all you need to do is send your original data to the web worker for processing. You use the same method as when you posted the message from the web worker to the UI thread but this time you perform it on the worker object within the UI thread, so you'll have something like this:


workerOne.postMessage([1,4,2,7,9,2,4,7,6,9,4]);


Now you have something that's a working demo, the array of integers (1,4,2,7,9,2,4,7,6,9,4) is sent to the web worker. The web worker starts up in it's own thread; picks that message up; sorts it and then sends the data back to the UI thread. The UI thread now has a sorted array of data but it hasn't actually done any processing to get that information. It has left the UI thread free, so to the user the system seems responsive. Ok, in this particular example with 10 or so integers there isn't going to be much of a difference, but when you're playing with millions of objects, this can have a significant impact.

Performance

While I was looking at this, I wondered if I could make use of Web Workers so that it would give some significant performance gains, especially in terms of data processing. If web workers work like standard threads then this should be fairly straightforward to test.

Here's my very simple test case:
How quickly can I sort three arrays containing two million integers each?

I'm going to test in three ways:
                1. Use standard javascript. Sort each array, one after the other and time how long it takes.
                2. Use a single web worker. The sorting of all  of the arrays will occurr in one web worker.
                3. Use a web worker for each array sort.

With what I knew about threads and web workers, I thought I'd find the following...
- The first and second test case would be comparatively similar in terms of time taken.
- The first test case would freeze the web browser until all data had been sorted. The other methods would not.
- The third test case would be the fastest, with all three sorting algorithms occurring in parallel. In theory, the time it takes for the third test case should be roughly 66% quicker than that of the first test case.

Each test case was repeated 10 times and an average time was taken, here are the results:

Test Case One: 11.24 seconds
Test Case Two: 13.75 seconds
Test Case Three: 7.21 seconds
(If you wish to actually repeat the demo yourself, you can pick up the files from here)

Interesting! Ok, I wasn't quite right about Test Case Three being 66% quicker, but it is around 33% quicker which isn't too bad. What is interesting is that test case two is almost 2.5 seconds slower than test case one. Just to open up a new web worker and to send/receive the massive arrays adds an extra 2.5 seconds to the processing time, that's almost a 22% time increase. That seems rather high to me but, it's good to know at least.

It's around about this time that I should mention just how the UI thread and worker threads post messages to each other as it can have an impact upon performance. You're transferring data across threads so you can’t just pass a variable by reference. Instead, you need to do a full copy of the variable. How this occurs depends on what you’re doing and how you’re doing it. If you’re passing across a string then the data will be serialized into JSON and sent to the worker thread. It’ll then be de-serialized at the other end. If however, you’re using a complex data type, File or Blob for example, then an algorithm called structured cloning will occur. This will effectively copy the contents of the variable, which for a variable containing megabytes worth of data, can be slow. There is however, another way! Google have come up with a concept of “transferable objects". This allows you to transfer the owner of an object from one thread to another using a zero-copy which is significantly faster. There is one down side to this: once you’ve transferred the object, you can’t then use it in the thread you transferred it from. It can only be accessed by the thread that has ownership. For more information on this, check out this page on HTML5 Rocks.

Ok, now I’ve got that covered, just out of interest, I thought I'd run the same tests as before but this time instead of using unsorted data I'd sort the data on already sorted data, making the sort function significantly faster (as it won't do anything meaningful). I was expecting to find the same sort of patterns as above, just with smaller numbers. Here's the actual results:

Test Case One: 1.91 seconds
Test Case Two: 4.10 seconds
Test Case Three: 3.22 seconds

Two interesting things are highlighted here:
  1. Test Case Two is slower than Test Case Three. Why? I haven't managed to find an answer to that yet. I can only assume that the overhead of sending all three arrays at once, which I wrap up into one object, performs badly when using the structured cloning algorithm to post messages to the worker thread.
  2. Test Case One is the fastest. This case doesn't use any fancy web workers, it's just plain old JavaScript executing each sort function one after another. So, by adding web workers, we've actually slowed down the data processing process, which is the exact opposite of what we were trying to achieve. The reason for this... the overhead of creating a web worker and communicating with it out-weighs the benefit we get by using a web worker and running data processing in parallel.
Eh? This makes things slower, not faster! What a waste of time!

Well, no. First, slower or not, the UI thread is always responsive when using web workers so, to your user, the system will seem faster than taking the traditional method. Secondly, although using web workers performed worse than the traditional approach in the last test, that won't be the case in all scenarios, as shown by the first experiment. If the overhead of creating a web worker and passing messages to and from it outweigh the amount of time saved by performing calculations in parallel on different web workers, then, yes, the overall performance will be worse, but, if you're performing a vast array of data manipulation on a great many records, then you should see a big performance gain. Like always though, it's best to see how it would perform with your actual data (or something similar). Only then will you be able to gauge just how much quicker Web Workers will make your web application, they are however a tool that you should definitely be aware of as we approach the on-coming HTML5 world!

Finally, if you want to follow this blog post up with further reading about HTML5 Web Workers, the best tutorial I found was posted on the Mozilla website, here.

Enjoy!