Some interesting news today: Amazon's S3 now supports CORS, the Cross-Origin Resource Sharing standard. This means that in addition to storing your images, stylesheets, and JavaScript files in S3 as you might be now, you can now also store any static data or templates you want to retrieve via ajax there, assuming your user is using a browser that supports CORS (all modern ones do, one way or another). This isn't a game-changer, there were ways to do this anyway (basically embedding those resources in JavaScript files a'la JSONP), but it just got a bit easier...
Saturday, 1 September 2012
Thursday, 23 August 2012
A reminder how Microsoft used to drive web innovation
As IE6 finally rides into the sunset,* Nicholas C. Zakas offers us a reminder of how, in a series of browser releases culminating in IE6, Microsoft introduced many of the key web innovations we use today such as innerHTML, access to all elements (not just forms and such), Ajax, modern events, and several others. This isn't in any way to discount what Netscape and others have done, but it's worth remembering that the browser everyone loves to hate was easily the best browser available when it came out. (Opera made a run at it soon thereafter, but never quite managed to take the lead, mostly because it didn't support legacy non-standard sites well. And then of course, along came Firefox, and then Chrome.) Good read, thanks Nicholas!
(* Unless — huge caveat — you're creating sites for China [21.3% market share], or arguably for Japan [4.7%] or India [3%].)
Tuesday, 14 August 2012
Measuring Scrollbar Size
Normally we want to avoid doing this sort of thing, but sometimes you just end up having no other option: Recently I couldn't avoid doing some sizing logic in JavaScript rather than CSS and markup, and I had to know the size of the scrollbars on specific elements. I found this post by Alexandre Gomes (which in turn was based on a MooTools forum thread; those forums are gone now), which shows a simple way to do it. I modified the code to measure both vertical and horizontal scrollbars and let you specify the element within which to measure in case the styling of that element affects the result, added some comments, and did some cleanup. Works a treat, I've tested it on a wide variety of browsers young and old with good results. Here's the code:
function measureScrollbars(container) {
var child, parent,
wWithout, wWith,
hWithout, hWith;
// Create a parent div with a fixed size
parent = document.createElement('div');
parent.style.width = "150px";
parent.style.height = "150px";
// Create a child div that's 100% of the width (granted
// that would be the default for a div) and which exceeds
// the parent's height
child = document.createElement('div');
child.style.width = "100%";
child.style.height = "200px";
// Put them in the DOM
parent.appendChild(child);
container.appendChild(parent);
// Measure the width without a scrollbar, then again with
parent.style.overflow = "hidden";
wWithout = child.offsetWidth;
parent.style.overflow = "scroll";
wWith = child.offsetWidth;
if (wWithout === wWith && "clientWidth" in parent) {
wWith = parent.clientWidth;
}
// Now make the child 100% height, and too wide
child.style.height = "100%";
child.style.width = "200px";
// Measure without scrollbar, then again with
parent.style.overflow = "hidden";
hWithout = child.offsetHeight;
parent.style.overflow = "scroll";
hWith = child.offsetHeight;
if (hWithout === hWith && "clientHeight" in parent) {
hWith = parent.clientHeight;
}
// Done
container.removeChild(parent);
return {
width: wWithout - wWith,
height: hWithout - hWith
};
}Or if you want the jQuery-ified version:
function measureScrollbars(container) {
var child, parent,
wWithout, wWith,
hWithout, hWith;
// Create a parent div with a fixed size
parent = $('<div>').css({width: "150px", height: "150px"});
// Create a child div that's 100% of the width (granted
// that would be the default for a div) and which exceeds
// the parent's height
child = $('<div>').css({width: "100%", height: "200px"});
// Put them in the DOM
parent.append(child).appendTo(container);
// Measure the width without a scrollbar, then again with
parent.css("overflow", "hidden");
wWithout = child[0].offsetWidth;
parent.css("overflow", "scroll");
wWith = child[0].offsetWidth;
if (wWithout === wWith && "clientWidth" in parent[0]) {
wWith = parent[0].clientWidth;
}
// Now make the child 100% height, and too wide
child.css({height: "100%", width: "200px"});
// Measure without scrollbar, then again with
parent.css("overflow", "hidden");
hWithout = child[0].offsetHeight;
parent.css("overflow", "scroll");
hWith = child[0].offsetHeight;
if (hWithout === hWith && "clientHeight" in parent[0]) {
hWith = parent[0].clientHeight;
}
// Done
parent.remove();
return {
width: wWithout - wWith,
height: hWithout - hWith
};
}Happy coding!
Wednesday, 8 August 2012
jQuery - Element cleanup update
For those who saw my jQuery - Cleaning up when elements go away post yesterday, I've updated it showing how we can do this right now, today, without waiting for the enhancement (or if the enhancement is never accepted). Oh, and the enhancement went from six lines to three. Many thanks to Dave Methvin for showing how (in both cases). Enjoy!
Tuesday, 7 August 2012
jQuery - Cleaning up when elements go away
(Updated 08/08/2012.)
Have you ever wanted to get a notification when an element is removed from the DOM so you could clean up? For instance, maybe you have events hooked on a different object (like resize on window) that you want to unhook when the element goes away.
Recently I wanted to, and since I know that jQuery does cleanup when elements are removed (so it can clear out event handlers and its cache for data), I wondered if it triggers an event for us.
It doesn't, but we can still get what we want quite cleanly. I'll describe what I'm hoping we'll be able to do tomorrow, and what we can do today.
Tomorrow (I hope)
We can enhance jQuery to give us an event on cleanup — with just three lines of code and virtually no overhead. Inside jQuery's internal cleanData function, just after the line that currently reads if ( data && data.events ) {, we add this:
if ( data.events.jqdestroy ) {
jQuery(elem).triggerHandler("jqdestroy");
}Boom, that's it. Now if we need notification when an element is going away, we just hook up the event:
$("selector_for_the_element").on("jqdestroy", function() {
// Do your cleanup
});We use triggerHandler rather than trigger because we don't want bubbling (there's another way we can avoid bubbling, but it requires a couple more lines of code, and triggerHandler is more efficient anyway — thanks to Dave Methvin for that!).
Here's a copy of jQuery 1.8rc1 with the patch, you can play with it here — that latter link is a test page that generates 10,000 elements, 5,000 of which we hook the click event on (so that they have something in data.events), and two of which we hook the jqdestroy event on. Then we call html on the container element to destroy them all and time how long it takes. You can compare that with this version using an unmodified version of 1.8rc1. For me, the times are much of a muchness (on Firefox 14, both versions average ~142ms when the jqdestroy event isn't hooked, and when it is [on two elements] the version that fires it averages ~163ms).
What I like about this is that if nothing has hooked the event, the overhead is at most one extra property check (the if ( data.events.jqdestroy )) per element destroyed (zero overhead for elements that haven't had any events hooked at all), but it enables a completely familiar and straight-forward way to get notifications.
Well, okay, but is there really a need for it? It would seem so: jQuery UI duck-punches cleanData so they can clean up; TinyMCE goes further, monkey-patching several API calls (empty, replaceWith, and others) so it can clean up an editor attached to an element. And of course, I wanted it for my plug-in that needs to unhook window.resize if there are no more active copies of it.
Now, let me clear about something: To my mind, using this event is a last resort. It's a big hammer, and if you used it on a lot of elements, removing those from the DOM could lag a bit. Consider this example which hooks jqdestroy on 5,000 of the 10,000 elements. For me, the elapsed times go from ~163ms when firing it on just two elements to ~450ms firing on 5,000 (again Firefox 14). Now, 5,000 is a lot of elements to hook this event (or any other) on, and anything can be abused, the point is just...don't abuse it. :-) The best use cases for this will be things like TinyMCE's editors, or grid plug-ins that need to handle resize in code, that sort of thing — where there will be only a few elements with the event hooked.
I've opened an enhancement request on the jQuery Trac database for this, offering to do the patch and send a pull request if the idea has legs. If you think this is a good idea, your support would be welcome! I'm not saying we have to do it the specific way I've outlined in this post, I'm totally open to other ways to get there. Three lines of code, near-zero overhead, and a familiar paradigm seems pretty good to me, though.
Today
But what if that enhancement doesn't get adopted? Or if we need to do this right now, today, with the current version of jQuery? Do we have to hack the jQuery file, or resort to monkey-patching?
Nope. In the linked Trac ticket, Dave Methvin showed how we can do it today, by adding our own "special" event and watching for the teardown on it. This uses the event system, but we'll never actually receive the event in the normal way. Here's how it works:
First, we create a "special" event:
$.event.special.ourowndestroy = {
teardown: function() {
// Handle it here, `this` is the element being clean up
console.log(this.id + " being destroyed");
}
};Then we force that to occur by hooking the event on the element, even though our handler will never get called:
$("selector_for_the_element").on("ourowndestroy", function() {
// This is never called
});Here it is in action using jQuery 1.7.2.
I've put a function there to make the point that the handler is never called (the action is in the teardown function); in reality I'd probably use $.noop or just false (shorthand for a handler that does return false) instead.
Now, when an element is being cleaned up, our teardown function will get called with this pointing at the element in question. Note that if we didn't hook the event on the element, we wouldn't force the teardown, so even though our handler isn't called, that's required.
Note: You'll also get the teardown call if you remove the event handler from the element (and then not when it's cleaned up, as it's not on there anymore), so if you're using this mechanism, either never remove the handler or handle the fact you get the call if you do.
So that's not an ideal way to do it, and it's not the way this stuff is normally done, but it's a passable workaround in the short term — and much better than monkey-patching jQuery's API on the fly.
Happy coding!
Thursday, 2 August 2012
Steve Sanderson's Round-Up of Eight Rich JS Libs/Frameworks
Steve Sanderson's done an interesting round up of the eight libraries and frameworks represented at the Throne of JS conference recently. The conference was about JavaScript applications, not web pages, and focuses on the kinds of projects that help you do your Model-View-Whatever stuff. Worth reading, bookmarking, and re-reading later. Steve declares his interest — he's on the KnockoutJS core team — but keeps it neutral, partially by staying very high-level. Which is exactly what I want from this kind of round-up.
Saturday, 7 July 2012
Well, I'm floored
How do you floor (or truncate) a floating-point number in JavaScript? (E.g., take a value like 5.7 and get just the 5?). The answer is simple: Use Math.floor. That's the right answer at least 99.99% of the time. It's clear, straightforward, easy to read, easy to maintain. It does what it says on the tin:
console.log(Math.floor(5.7)); // "5"
Sorted.
But you see people doing other things in the name of "performance," which is the purpose of this post: Primarily, to explain what they're doing; and also to see how much actual benefit they're getting from it.
Why performance? On rare occasions, you may have an operation where you need to squeeze every last bit of performance out that you can. The theory here is: Function calls are cheap, but they aren't free, and unless the JavaScript engine you're using does static analysis of your code, when call Math.floor it has to look up the Math identifier (which means walking the scope chain to see if it's been shadowed, before ultimately finding it at the outermost level, the global object), look up its floor property, and then call the function that property points to. So if there's a more direct route, people want to take it when they're looking for every last cycle.
And what they turn to is bitwise operations. JavaScript only has floating-point numbers, of course, but its bitwise operations are defined in terms of 32-bit integers. So when you apply those operations to a number, the first thing that happens is that the number is turned into an integer (whole number) by just chopping off any fractional part (see the internal ToInt32 operation for details). Chopping off the fractional portion is, of course, floors the number — exactly what we want. (Well, with a caveat: The bitwise operators "floor" positive numbers, but they "ceil" negative numbers. "Floor" always goes down, and of course for negative numbers "down" is away from zero rather than toward it; so Math.floor(-12.1) is -13, not -12. When you just chop off the fractional part like the bitwise ops do, you get -12 instead.)
There are lots of operations to choose from that will floor the number without actually changing its value; I'll list them in rough order of how often I've seen people use them:
- Double bitwise NOT:
~~num - Bitwise OR with zero:
num | 0 - Left bitwise shift, but not really shifting:
num << 0 - Right bitwise shift, but not really shifting:
num >> 0
- Unsigned right bitwise shift, but not really shifting:
num >>> 0 - Bitwise AND with all-bits-on:
num & 0xFFFFFFFF - Double bitwise XOR with zero:
num ^ 0 ^ 0(or indeed, any other number, but zero is easy to type)
But do they really go faster? As always, it depends on what engine you're using:

Figure 1
Math.floor vs. the bitwise operators
(click image for full-size version)
(interactive version on jsperf)
(Compare only the operations on the same browser; the different browsers were run on different machines, so their speed can't be usefully compared with each other.)
The first take-away from that chart is: Things ain't like they used to be. It used to be that the bitwise operators were a lot faster than Math.floor. But engines have really stepped up their game in terms of scope chain resolution speed and function call overhead/inlining. (To give you an idea: IE7 does the bitwise OR with 0 nearly nine times faster than Math.floor, much more dramatic than any of the results above.)
The second take-away is: On most engines, yes, the bitwise operators are faster than Math.floor, either very slightly faster, or markedly faster. The outlier here is Firefox 3.6, which must have some specific Math.floor optimization as it screams past the bitwise operators. More recent versions of Firefox don't show that behavior.
The third take-away is: All bitwise operators are not equal. Looking at the chart, the best on most engines is the bitwise OR with zero (num | 0; the bright red lines) — unless you're using Safari. The most reliable all-rounder (performs well across engines, even if not in first place most of the time) is, oddly, the signed right-shift (num >> 0; the reddish-pink, second from the bottom of each grouping).
And finally, we can't tell this from that chart per se, but it's worth noting that using the bitwise operators tends to give you the greatest benefit on the slowest engines; e.g., there's not much in it on recent Chrome or Firefox, but there's a much larger difference on the slower IE8, IE9, Opera, and Safari engines (again, Firefox 3.6 seems to be the outlier here).
So if you've been wondering what that n = n|0 was doing in that code you saw, now you know; it's chopping the fractional part off n — either for performance reasons, or because the coder wanted 12.7 to become 12 and -12.1 to become -12 rather than -13. And it looks like, in those very rare situations where it matters, you do actually get a performance benefit where you need it using the more-obscure, but faster bitwise operation to get the job done. My recommendation: Just be sure to comment what you're doing. :-)
Happy Coding!