Ajax Bestiary: A Javascript Field Guide
 
Ajax Bestiary: A Javascript Field Guide
 
 

Entries Tagged as 'Browsers'

Vibration API coming to Firefox 11

Posted by Dave Mahon

The current Aurora release of Firefox includes the Vibration API, a very simple system for making devices rumble.

The API consists of a single call to navigator.mozVibrate().

The function accepts a single parameter. Pass a positive integer to indicate the number of milliseconds the device should vibrate. Pass an array of these integers to create a vibrate pattern. Finally, pass 0 to stop any current vibration.

navigator.mozVibrate(2000);
//Vibrate for 2 seconds
 
navigator.mozVibrate([1000, 1000, 500]);
//Vibrate for a second.
//Then pause for a second.
//Then vibrate for another half-second.
 
navigator.mozVibrate(0); //An empty array is also valid
//Stop vibrating

Obviously, this is only meaningful on devices that support vibration, like mobile phones, tablets and game controllers. However, in both the Firefox implementation and pending W3C specification, calls are silently ignored when the device does not support vibration or vibration is not allowed.

The W3C added a NotSupportedError that is thrown when invalid values are passed to the function. Obviously, it has also generalized mozVibrate() to navigator.vibrate().

The specification also checks document.hidden before the rumble begins and at any time the visibilitychange event is triggered. If document.hidden is false, any requested vibrations must be ignored and any current vibration must cease immediately. No feedback is provided to your code in either of these events.

This means that spam pages can’t drain your battery (unless you leave the offending page up), a concern expressed on the WebKit mailing list and is implemented as navigator.webkitVibrate() in the development builds of the WebKit core.

HTTP Header Issue in Mobile Safari Can Break AJAX

Posted by Dave Mahon

Mike Swieton has reported a bug in Mobile Safari on iOS 5.1.

The bug occurs on AJAX-heavy sites that let you download content. Specifically, he experienced it when he clicked to view a PDF inside Mobile Safari and then used the back button to return to the site. Subsequent AJAX requests had the OPTIONS verb instead of the expected GET, something the web server obviously would not expect.

Fortunately, he came up with a fix. If you change the Content-Disposition HTTP header from attachment to inline, the browser does not lose track of the current domain and thus does not change the verb used for AJAX requests.

Page Visibility API

Posted by Dave Mahon

To date, it has not been easy to tell, using JavaScript, whether the user can see your page or not. Sure, we have load, focus, blur and unload, but these have proven quirky and inconsistent in the past. Certain environments give us the ability to jump between windows and tabs, and even scroll pages without giving focus to the browser window. Automatic lock screens leave your web page active, but inaccessible. Further, Google is developing a feature for Chrome wherein a page can load and render before it is made visible to the end user.

If you’ve ever received a message on Facebook when it was the selected tab, but not necessarily the selected window and application, and it hasn’t made a noise, you’ve experienced some of this quirkiness.

So what can you do with this new API? You can slow down your application, suspend timers and clocks, and generally make your page behave better in a cooperative multitasking environment. In short, still more of what used to require Flash to implement no longer does.

Chrome introduced this new, simple API in 13 and the W3C has a group standardizing it. Firefox and IE will both see it added in their respective version 10 browsers.

To use it, you really only need to know two properties and one event.

The document.visibilityState property can be any one of four values, but the two most common (and only required) ones are hidden and visible. Now, when the page loads, you can know whether your content is actually exposed to the user or not.

The document.hidden provides a simple boolean.

Happily, the standards do partially specify how other applications can interact with these properties:

As examples, the attribute returns true when:

  • The User Agent is minimized.
  • The User Agent is not minimized, but the page is on a background tab.
  • The Operating System lock screen is shown.
  • The User Agent is minimized and a preview is shown.

The visibilityChange event will fire when this state changes after the initial page load, so you needn’t check it obsessively.

Note that Chrome uses the webkit prefix for this API, its properties and its event. Firefox and IE are expected to use the W3C version, without prefixes.

Loopy Optimizations

Posted by Dave Mahon

We all know that code optimization is important, especially when processing large quantities of data. It is also common knowledge that adding layers of code to loops reduces performance. Except this maxim doesn’t always hold when it comes to JavaScript in browsers and even native methods can vary wildly in performance. In fact, in almost all cases, Underscore, jQuery and YUI outperformed any of the native methods. Interestingly, the newest implementation for native looping, forEach, consistently trumped a traditional for (var i = 0; i < 2500; i++) loop.

I set up a testing framework that looped through a normal array instantiated like so:

var data = [];
var v = {}; //This value doesn't seem to affect performance at the data size I chose
 
for (var i = 0; i &lt; loops; i++) { //loops is defined elsewhere
   data.push(v);
}

I looped through this array using the following methods:

  • for loop
  • for … in … loop
  • forEach loop (not supported in IE9 Quirks Mode)
  • Prototype 1.7: Enumerable.each
  • jQuery 1.7.1: $.each
  • Underscore 1.2.3: _.each
  • YUI 3.1.4: YUI.each

Each loop was passed the value of the array element and returned immediately, like so:

//From the native for and for ... in ... tests
(function(el){return;})(data[i]);

I eventually settled upon an array of 2500 elements and running the test 200 times to collect a reasonable number of samples. These numbers were not chosen arbitrarily. Prototype would time out on Firefox at 5000 array elements and Safari seemed to have wildly varying results on each run of the suite with fewer than 200 samples. With 200 samples, the variance in mean time between runs became a few hundredths of a millisecond, not enough to be of consequence. Disturbingly, while Prototype froze the browser with 5000 array elements and 100 samples, it had no issue with 2500 elements and 200 samples. Even so, with some tests averaging less than a hundredth of a millisecond, we will soon require much larger data sets to get meaningful results at all, which may preclude the inclusion of Prototype (and even native methods!) in future tests.

All tests were run in a freshly launched browser on an updated operating system (either MacOS 10.7.2 or Windows 7 Home Premium) running on a MacBook Pro with a 2.53GHz Intel Core 2 Duo processor and 4GB of 1067MHz DDR3 RAM. Firefox had all add-ons disabled and Internet Explorer had the Developer Tools open (to switch between Standards and Quirks mode).

So let’s look at some charts!

Mac safari
This was certainly an interesting start to the process. YUI, Underscore and jQuery all clocked in at 0.005 ms. Prototype would prove to be faster than native methods, with the exception of forEach, on all browsers. Underscore was only be outperformed on IE 9 (32-bit, Standards Mode).

Mac chrome
Chrome was exceptional as well, with the traditional for loop actually running slower than for ... in .... This behavior was also seen on Chrome for Windows and Safari for Windows.

Since all of the major browsers are clearly pre-optimized for these libraries (as they themselves wrap the native looping language structures), let’s look at just the libraries:
Loop run times, by library
Here we can begin to see that Prototype really is behind its peers in loop performance. While we are talking fractions of a millisecond, our apps are growing larger by the day and this could become a serious issue.

Run times of non-prototypical libraries by browser
Hey! It looks like Firefox really is slow. Curiously, IE 9 is significantly faster, which flies in the face of most generalized JavaScript performance metrics.

Still, something looks odd about IE:
Run times by library and version of Internet Explorer 9
Your mileage varies wildly depending on whether you choose standards or quirks mode, and not always in obvious ways. In general, 64-bit is faster, but only marginally, and most people are not using it. (You have to explicitly launch it, as it is not the default, even on 64-bit Windows). Meanwhile, quirks mode apparently embeds some performance hacks. As a note to benchmark developers, this should be evidence enough that not all IE’s are the same and we need to start breaking down by rendering mode and compilation.

So far, we’ve seen the average times and most browsers are quite acceptable. What are the worst case scenarios?

Platform

Browser

Method

Max (ms)

Mean (ms)

Windows 7

IE 9.0.8112.16421 (64-bit IE 9 Quirks)

for

93

5.29

Windows 7

IE 9.0.8112.16421 (32-bit IE 9 Standards)

forEach

81

4.04

Windows 7

IE 9.0.8112.16421 (64-bit IE 9 Quirks)

for in

81

6.27

Windows 7

IE 9.0.8112.16421 (32-bit IE 9 Standards)

for in

76

9.87

Windows 7

IE 9.0.8112.16421 (64-bit IE 9 Standards)

for in

71

4.89

Windows 7

IE 9.0.8112.16421 (32-bit IE 9 Quirks)

for in

67

5.995

MacOS 10.7.2

Firefox 9.0.1

for in

55

1.885

Windows 7

Firefox 9.01

for in

52

6.055

Windows 7

IE 9.0.8112.16421 (32-bit IE 9 Quirks)

for

49

4.66

Windows 7

IE 9.0.8112.16421 (64-bit IE 9 Standards)

for

48

4.76

Windows 7

IE 9.0.8112.16421 (32-bit IE 9 Standards)

for

39

7.845

Windows 7

Chrome 16.0.912.75 m

for in

30

1.13

Windows 7

Chrome 16.0.912.75 m

for

26

1.315

MacOS 10.7.2

Chrome 16.0.912.75

for

23

1.175

MacOS 10.7.2

Chrome 16.0.912.75

for in

22

1.085

MacOS 10.7.2

Safari 5.1.2

for in

16

1

Windows 7

Firefox 9.01

jQuery

6

0.185

MacOS 10.7.2

Safari 5.1.2

for

5

0.52

MacOS 10.7.2

Firefox 9.0.1

for

5

0.7

Those averages hid some extreme variations within Internet Explorer. Fortunately, most of these are found using native language structures, which we know better than to use.

The sound of music is silence and sometimes a click

Posted by Dave Mahon

HTML5 begat the AUDIO tag. Now that we have it, what do we do with it? And how do we accommodate older browsers?

Unfortunately, there are two incompatible standards and the W3C Audio Working Group "has not decided upon a specification".

The Web Audio API works on recent builds of Chrome and Safari. The API includes complex filters and allows developers to roll drum machines and visualizations. It’s active by default on Chrome 16, but not on Safari 5. Worse, Safari 5 reports that it is supported, but won’t run the samples to which I have linked. Adding insult to injury, it’s also slow and can randomly introduce skips and clicks.

Mozilla introduced the Audio Data API, but it only works in Firefox 4 and above. It’s also a very low level API and requires intermediate libraries to be truly useful for non-developer apps, of which there are a number. Like Google’s Web Audio, it’s slow and can randomly introduce skips and clicks.

Since these two technologies encompass only about half of web traffic, we clearly need fallback mechanisms.

There is SoundManager2 which uses both HTMl5 and Flash 8 or 9+ to bridge platforms. It relies on MP3/AAC/OGG/WAV sample files and supports panning, sampling and – most valuable – event support. Events like whileplaying and onposition make it easy to sync your audio and video. Beyond equalization, volume and start/stop positions, however, you can’t do much to filter the sound output.

You might also try Audiolet, which lets you generate your own waveforms in browser, giving you a full range of freedom, but it’s going to sound like 8-bit audio unless you use samples. (Hint: try combining it with MUSIC.js to make the most of that 8-bit arcade sound)

Then there is audiolib.js, which goes even lower than Audiolet and can operate server-side. It allows you to both manipulate and generate audio samples in PCM format, which it can then save for future use.

Audiolet starts quickly and is half the size of SoundManager2, but can click and skip, especially when the browser is scrolling or otherwise pre-occupied. SoundManager2 can bog down when playing too many sounds at once. Try activating +follow and then moving your mouse quickly over its Smashing Christmas Lights demo to see this in action.

Audiolib is extremely low level, but for generating short realistic waveforms, it is effective and fast, both client-side and server. Sadly, in Firefox 9 on my Mac, this example only plays the first bell while Safari 5 and Opera 11.6 played nothing at all. Chrome 16 played it correctly. However, when I had the page open in 3 browsers simultaneously, even though only one was generating noise, the load was causing skipping and clicking in Chrome. Your audio could easily suffer if the end user’s computer is otherwise busy.

In short, there is no good solution yet that is widely supported and flexible and performant, even within modern browsers.

Internet Explorer 6 market share falls below 1% in US

Posted by Dave Mahon

Microsoft has proudly announced that IE6 was used by only nine-tenths of the web surfers in the US in December 2011. The US joins Austria, Czech Republic, Denmark, Finland, Mexico, Norway, Philippines, Poland, Portugal, Sweden and Ukraine in their champions circle, nations with an IE6 penetration of less than one percent.

Belgium, Colombia, Indonesia, Netherlands, and Turkey are all poised to join them, at 1.0 to 1.2%.

Asia is still, regrettably, home to a great many IE6 users. Fully a quarter of Chinese web traffic is on IE6. South Korea is at 7.2%, Japan is at 5.9%, Vietnam weighs in at 5.5%, India is at 5.4% and Taiwan is only slightly better at 4.9%. If your website serves significant numbers in these markets, consider encouraging users to upgrade.

Who Uses Ajax Bestiary

Posted by Dave Mahon

Happy New Year! I thought the first working day of 2012 for most of us marked a good occasion for reviewing what you, the web developer, are using to access this site (and presumably develop). Some of the numbers were surprising. From the return of IE, to the appearance of mobile devices in the top 10 display resolutions, to a spike in traffic from the Arab peninsula, you did the unexpected.

For the purposes of this comparison, I looked at the months of December 2010 and December 2011 using Google Analytics. All numbers are based on total visits to simplify the comparison.

Operating Systems: Windows… and Sony

You’re still mostly on Windows, but that margin is narrowing significantly; Microsoft’s operating system went from 72% of our readers to 62%. Of that, 53% was running Windows 7, while slightly more than a third of you have held on to Windows XP, down from 45% in 2010.

MacOS and Linux also saw declines, from a combined 27% to just 15% of our visitors.

The big winners were PlayStation 3(!) which went from 0 visits to 10.2% of traffic and Android, which went from less than one-tenth of a percent to more than 3.

Browsers: Microsoft Turns Around

Developers seem to expect their browsers to behave well with modern HTML, CSS and JavaScript features.

Last year, a mere 11% of you were visiting Ajax Bestiary on any version of Internet Explorer, but the widespread adoption of versions 8 and 9 turned that around. You are once again the predominate browser, with just under a quarter of the traffic. Sadly, Internet Explorer 6 also saw a spike, from 29 visits last year to 125 this year.

Firefox plummeted precipitously, from more than half of all traffic to 23% of it, with 75% of you on versions 6 and above, though curiously, there was a single visitor using version 3.0 Beta 1.

Chrome users can’t gloat though. While more than 75% of you are on versions 15 and 16, your share fell 6 percentage points to 24%.

Mobile devices are still a small fraction of our user base, at just 7% of visits. That said, they did grow an astonishing 1277% over the same period last year. Of those, Apple products represented only 18% of traffic. You are, apparently, an Android-based community, though RIM and Nokia saw increases as well. Opera Mini saw a sharp spike in traffic, which we will come back to momentarily.

Displays: Screen Sizes Grew – And Shrunk

The top 10 screen resolutions for December 2011 were 1280×1024, 1024×768, 1366×768, 1280×800, 1920×1080, 1440×900, 1680×1050, 1920×1200, 1600×900 and 320×480.

Half became more common (increasing by 13.66 percentage points) and half became less (declining by 24.1 points). All told, however, these resolutions were in use by more than three-quarters of all visitors.

Curiously, the largest increase was in 1024×768, which nearly doubled. Meanwhile, 320×480, a resolution used by some mobile phones, grew by a full 2 percentage points.

Where You Are: Probably Not The USA

Consistent with last year, two-thirds of our traffic use English as their default language.

Thirty percent of our visitors are from the US, up from 22% in 2010. California, Illinois, New York and Texas make up a third of that traffic. Almost every state visited us in December 2011. Montana, why don’t you love us?

The largest increases were in three regions: Unknown, the Middle East and the Caribbean.

Traffic from the mythical country of (not set) rose 7325%, though 90% of that was actually Opera Mini, which renders pages on their internal servers and presents them to the mobile device, obfuscating device and geolocation data in the process.

Almost all of the Middle East saw an increase in traffic, but a few countries stood out. Qatar rose 3700%, Saudi Arabia rose 3175%, UAE rose 1460%, Iraq grew 400%, while Oman and Yemen each rose 100%.

In the Caribbean, Puerto Rico increased 1800% and Trinidad and Tobago rose 233%.

Finally, Slovakia went up by 233%, Latvia went up by 200% and Algeria went up by 150%.

Sanity Check

Since some of this seems so anomalous, I pulled up the report for all of 2011.

Internet Explorer slipped to just 16% for the year. The transition to IE dominance actually happened in September. Meanwhile, Playstation users saw a steady climb throughout the year.

Windows rose slightly 65% and MacOS and Linux returned to a combined 22%. All three platforms still slipped from 2010.

For displays, 320×480, #10 in December, slipped to #14, with 1024×768 falling to fourth place.

In the US, Florida actually edged out Illinois and it appears that Montana was simply on vacation in December. We knew you loved us!

Outside the US, we saw traffic from 34 African countries, 42 countries in the Americas, 48 from Asia, 44 from Europe and 7 from Oceania.

Bring HTML5 and ECMAScript 5 to a browser near you

Posted by Dave Mahon

Unless you develop in-house sites for companies that have standardized on a very modern browser, you’re stuck developing sites for IE8 and even IE7. (Heaven help you if you’re still developing for IE6).

How then do you access some of the powerful features of ECMAScript or the contextual tags of HTML5 without having to write layer upon layer of fallbacks?

Your fellow JavaScript developers have produced shims to emulate most of this functionality, even in environments where Chrome Frame isn’t viable.

The html5shiv project is still under active development. It not only adds support for HTML5 contextual tags, it sets their default styling and makes them print in IE8 and below. Naturally, their canvas element is not going to have the behaviors you see in other browsers, but at least you can get away with a single set of markup and fewer CSS rules.

The es5-shim project is also under active development. It alters prototypes of native objects, so I wouldn’t combine it with prototype.js. This library also has the benefit of being well documented – including what does and does not differ from the specification. Heed the cautions from Kris Kowal, its author, though:

“As closely as possible to ES5″ is not very close. Many of these shims are intended only to allow code to be written to ES5 without causing run-time errors in older engines. In many cases, this means that these shims cause many ES5 methods to silently fail. Decide carefully whether this is what you want.

GPG4Browsers: Site functionality via browser extensions

Posted by Dave Mahon

I’m not sure how I feel about having to install browser extensions to unlock the full potential of a site (It reminds me of Pepsi’s site, circa 1997), but some functionality simply isn’t practical without it.

GPG4Browsers, for example, performs browser-based PGP Gmail message encryption, storing the encryption keys as a browser setting, which from a usability perspective, makes a lot of sense, because it means that the entire experience can be nearly transparent to the user, or require minimal retraining.

For now, this only works in Chrome, but Firefox support is under development (and presumably similar behavior will be possible in IE 10). Naturally, it also has security implications stemming from Javascript’s lazy garbage collection and wide open variable scope, in addition to the usual concerns about browser security.

While GPG4Browsers is clearly a case of progressive enhancement, I can’t help but wonder if JS-based extensions could actually lead to browser lock-in.

Unexpected call to method or property access

Posted by Dave Mahon

If you’ve ever used jQuery’s append or prepend methods in IE8 with complex HTML fragments, you’ll probably recognize this message. I ran into it very recently when I was loading relatively simple HTML containing a relatively complex script into a modal window.

Naturally, the bug only occurred in Internet Explorer and the failure happened at line 4 of this block:
append: function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 ) {
this.appendChild( elem );
}
});}

This seems like the least likely point of failure imaginable, but there was the error preventing the rest of the script from executing.

I found plenty of theories. There were some recurring themes though.

First, it is critical that you append well-formed HTML or the browser may justifiably fail. I tested mine fragment by wrapping it in some very basic HTML, HEAD and BODY tags with a DOCTYPE declaration and feeding it to the W3C Validator. That, unfortunately, did not work.

I disregarded the theories about buttons, because I had other scripts that referenced buttons and they worked fine.

One commenter (zmonteca) in the jQuery forums mentioned, “DispHTMLCommentElement,” which got me thinking. What exactly were this and elem and the moment of failure? After adding this to the Watch variables, I saw the problem. At some point in the loop, this became the SCRIPT element and elem became the DIV. Infuriatingly, at earlier iterations, the same nodes were in the correct order!

Now it all made sense. Both are valid HTML DOM nodes of type 1 (element), but it makes no sense to the browser to embed a DIV inside of a SCRIPT, just as you wouldn’t embed a BUTTON inside of an IMG. It would be downright… unexpected!

So the morals of the story are

  1. Always write clean, valid markup
  2. Be comfortable performing stack traces
  3. Really understand not just JavaScript, but HTML as well

Oh, and are you’re wondering how I dealt with the situation? I’ll own up to introducing a hack-ish patch to my copy of jQuery 1.7. I simply checked the tagName property of this and if it is SCRIPT, I reverse this and elem. This particular project is unlikely to have dynamically loaded OBJECT tags, so this seemed the fastest, cleanest way to deal with a bad issue when the markup itself validated.