Recently on Beyond Standards
Web Workers are part of HTML 5 and already featured in Firefox 3.5 and Safari 4. A worker is a script that can be dynamically loaded by the main page (or other workers). it runs in isolation in a background thread and only communicate with its caller through string messages.
They can be used to to increase user interface responsiveness by taking care of computations that would otherwise run in the main UI thread.
The UI freeze
Let’s see what happens when we run a long computation in the main thread. Try clicking on all checkboxes during the computation and notice how all clicks are queued and processed once the computation finishes (read about asynchronous events and timers).
Workers to the rescue!
Let’s run the same computation but this time inside a worker. Again, try to click the checkboxes (you need Firefox 3.5 or Safari 4), see how the UI responds immediately?
The setTimeout pattern
Traditionally, to prevent blocking the browser, one would break long computations into smaller ones and use setTimeout to schedule execution as Julien Lecompte explains.
He applies this method to sort an array. Every pass through the array is scheduled to run with setTimeout:
function sort (progressFn) {
var i = 0;
(function () {
... // sorting code here
i++;
progressFn(i, length);
// schedule the current function for execution
if (i < length) {
setTimeout(arguments.callee, 0);
}
})();
}
Try it : sort without worker
Sort with a Worker
Now let’s put his sorting code into a worker, it should run a lot faster (no callback overhead) and has the advantage of not mixing scheduling with sorting code:
function sort (progressFn) {
i = 0;
var sort_loop = function () {
... // sorting code here
i++;
progressFn(i, length);
if (i < length) {
sort_loop();
}
};
sort_loop();
}
Try it: sort with worker (you need Firefox 3.5).
There you go, UI responsiveness without the pain of chopping your code into digestive chunks !
While Workers are not yet implemented in all browsers (the spec is still evolving), be prepared! By allowing us to separate UI from application logic and giving us multiple threads of execution, Workers will help us build bigger and better web applications… and maybe overthrow that funky boss !
Related links
How Javascript Timers Work
Running CPU Intensive JavaScript Computations in a Web Browser
Computing with Javascript Web Workers
Mozilla Dev Center: Using Web Workers
To carry on with Javascript, I’m going to talk about a little circular problem I ran into today while dynamically inserting elements into a page.
Let’s say you have a page with a list and you want to do something when someone clicks on the list items:
<ul id="taskList">
<li>first item</li>
<li>second item</li>
...
</ul>
Typically, with jQuery you would attach handlers to the list items like so:
$(document).ready(function(){
$('#taskList li').bind('click', function(){
doSomething();
});
});
So far so good, but suppose you want to insert a list under the element you click on? You will also need to attach handlers for the items you’ve inserted! Let’s see:
$(document).ready(function(){
$('#taskList li').bind('click', function(){
insertSublistUnder(this);
// now let's attach the new handlers
$(this).find('li').bind('click', function(){
insertSublistUnder(this);
// now let's attach the new handlers...
// hey, wait a minute !!!!
});
});
});
You see the pattern here, it could go on and on !!!
So how do you do this?
Short answer: if your version of jQuery is 1.3+, use live instead of bind to attach the handlers (this ensures that all <li> inserted in the future will have their handlers bound automatically:
$(document).ready(function(){
$('#taskList li').live('click', function(){
insertSublistUnder(this);
});
});
But what do you do if you’re stuck in pre-1.3 land ?
Let’s see, we are attaching handlers which in turn insert some items and… attach some handlers which…
We have a bit of recursion here:
$(document).ready(function(){ <------------------
$('#taskList li').bind('click', function(){ |
insertSublistUnder(this); |
// here call this ------------------------/
// on the newly inserted items
});
});
Let’s pack the recursive snippet into a function, say, ‘ attachHandlersUnder’, which takes a (clicked) list element as a parameter:
function attachHandlersUnder(li){
$(li).find('li').bind('click', function(){
insertSublistUnder(this);
attachHandlersUnder(this); // recursive definition
});
}
$(document).ready(function(){
attachHandlersUnder('#taskList'); //
});
Et voila !
Well, in essence… It is actually a bit more complicated, since calling ‘bind’ repeatedly on an element keeps adding handlers to the ones previously set.
Here’s a file with the final code.
This post talks about Javascript and the unfortunate combination of two quirks which can cause a few surprises.
Quirk 1: + as addition and concatenation
Javascript, unlike other languages use the same symbol for number addition and string concatenation:
1 + 1 => 2
'1' + '1' => '11'
Quirk 2: implicit type conversion
Javascript does not always throw an error when evaluating expressions with an odd mix of values and operators, such as, ‘10′ / ‘5′, instead it tries to converts values behind the scene (yes, you should be scared). Usually strings involved in arithmetic operations are converted to number, so :
'10' / 5 => 10 / 5 => 2
So it seems safe to assume that string representation of numbers will be treated as numbers in arithmetic operations, right ? Not so if the + operator is involved! Remember:
'1' + '1' => '11'
Form and formula
Suppose we have a form that asks for two numbers, and some Javascript which calculates the average. Let’s say the user types ‘1′ and ‘1′:
// Form values are strings
var number1 = $('#number1').val(); // '1'
var number2 = $('#number2').val(); // '1'
var average = (number1 + number2) / 2 ; // 5.5 !!
we get 5.5 instead of 1 because (number1 + number2) is concatenation and not addition.
The workaround in that case is to convert the form values to numbers beforehand :
var number1 = Number($('#number1').val()); // 1
var number2 = Number($('#number2').val()); // 1
var average = (number1 + number2) / 2 ; // 1
What makes this especially bad, is that the program appears to be working; it just silently returns the wrong result ! So remember, be cautious when using strings and addition in Javascript…

[Images via Gizmodo]
It appears that not only have Microsoft been poring over my posts here on Beyond Standards where Apple have failed to meet my meagre needs, Asus apear to have taken it a step further.
With a spanking new prototype on display at CES, the Asus Eee Keyboard PC looks like a brilliant idea.
Where I only asked for a stand-alone multi-touch trackpad, Asus have taken the concept one step further by cramming an entire ultra-portable PC into a keyboard with most of the industrial design queues of Cupertino’s finest.

With a built in touchscreen instead of the customary number pad you could have everything from a calendar to email and RSS widgets on there, instantly hot-swappable with a number pad or even bespoke gaming or multimedia control. Genius.
Now if they could just create a simpler version which is just a keyboard and trackpad so I can buy one for work and at least 2 for home I will be a happy man!
Way back in March I wrote a little missive imploring the good people of Cupertino to bring out a trackpad to replace the old-fashioned Microsoft mouse lurking just to the right of my decidedly svelte Apple keyboard, but it appears that it may be the Microsoft folks in Redmond who hit that particular milestone first.
Lets just hope that they make it look nice, feel nice, and work well… unlike Vista (sorry - I had to say it. We’ve got a Vista machine at home and I had to use it recently when the VPN to work stopped playing nice with my MacBook, and I just can’t use Windows any more - it makes me want to break things).
I know Apple have a chequered history when it comes to the humble pointing device (i.e. they’ve never really made a good one), but it just seems to be a no-brainer when they’ve already got the technology in place in the MacBook Pro line (and the iPhone), they’ve already got a simple aesthetic that it could fit into very nicely, and they’ve got an image-conscious target audience who would benefit from the interface options that it would present.
Surely I’m not the only one who thinks that a multi-touch trackpad would pretty much kick ass in place of the old-school mouse? Am I?
Bueller? Bueller? Bueller?..