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

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.

Enyo released

Posted by Dave Mahon

HP is slowly open sourcing webOS. Yesterday, they released the Enyo framework with cross-browser support.

The heart of Enyo is the enyo.kind() method which dynamically generates a reusable page component which can be referenced in the global namespace like so:

enyo.kind({
    name: "Hello",
    kind: enyo.Control,
    components: [
        {name: "hello", content: "Hello From Enyo", ontap: "helloTap"},
        {tag: "hr"}
    ],
    helloTap: function() {
        this.$.hello.addStyles("color: red");
    }
};
 
// make two, they're small
new Hello().write();
new Hello().write();

At first glance, this seems like a lot of extra code to create a bit of color-changing text with a horizontal rule. However, you can also define custom properties, events and methods, which suddenly makes this an elegant way to create what jQuery calls plugins. Since you can also encapsulate other generated kinds, this could also be an interesting way of creating entire actors within a game.

While it’s not so performant as to empower, say, a first-person shooter, they do provide a simple demo of a game.

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.

HTML5 Interactive Maps for Both Mobile and Desktop

Posted by Dave Mahon

When you think maps, you probably think Google or MapQuest, both of which have interactive maps that are really only optimized for desktop browsers. You have to jump out to a separate app for geo-interactivity (yes, that is an invented word).

That is perhaps why CloudMade released Leaflet, putting it under the BSD license.

As you would expect, it supports tile layers, polylines, markers, popups and image layers. However, it also has native support for panning and zooming on mobile browsers. It also uses CSS3, so you can stylize pins, popups and controls. It’s also fast – noticeably faster than Google Maps – though that is partially because its source data, OpenStreetMap, doesn’t contain quite as much data.

At this time, supports most desktop browsers well, but on mobile environments, it requires iOS 3+ or Android 2.2+.

Implementing a map is very straightforward:

// create a CloudMade tile layer
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/YOUR-API-KEY/997/256/{z}/{x}/{y}.png',
    cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
    cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});
 
// initialize the map on the "map" div
var map = new L.Map('map');
 
// set the map view to a given center and zoom and add the CloudMade layer
map.setView(new L.LatLng(51.505, -0.09), 13).addLayer(cloudmade);
 
// create a marker in the given location and add it to the map
var marker = new L.Marker(new L.LatLng(51.5, -0.09));
map.addLayer(marker);
 
// attach a given HTML content to the marker and immediately open it
marker.bindPopup("A pretty CSS3 popup.<br />Easily customizable.").openPopup();

Leaflet generated map

Remote console for mobile web diagnosis

Posted by Dave Mahon

Remy Sharp has developed a tool for remotely debugging web pages. This works using code injection, so be very sure to keep it out of production environments. However, when you need to diagnosis issues remotely, say, because it’s on a mobile device, with limited console support, or because a client is reporting problems that you can’t repeat locally.

Implementing this is a snap!

:listen

This returns an UUID which you will need to insert into the page markup:

<script src="http://jsconsole.com/remote.js?FAE031CD-74A0-46D3-AE36-757BAB262BEA" type="text/javascript"></script>

From then on, calls to console.log() will return their output to your listening machine.

The really handy library has one more trick up its sleeve. You can specify the UUID to which you will listen.

:listen FAE031CD-74A0-46D3-AE36-757BAB262BEA

When the remote device loads the debugging module, you’ll see something like this in your console:

:listen FAE031CD-74A0-46D3-AE36-757BAB262BEA
Creating connection...
Connected to "FAE031CD-74A0-46D3-AE36-757BAB262BEA"
Connection established with Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8

Incremental MD5 with AMD support

Posted by Dave Mahon

As we all know, MD5 is a fast hashing algorithm. While its numerous security holes make it undesirable for encryption, it is pervasive and convenient for quickly generating quasi-unique ID’s.

While JavaScript has no built-in support for hashing algorithms, this wheel has been re-invented a lot. So why discuss it here? Most implementations to date have littered the namespace with variables or offered poorer performance than their rivals.

SparkMD5 attempts to remedy this situation. Based on the JKM md5 implementation, it is fast. However, it also keeps namespace pollution to a minimum, with its use of closures and OOP.

In addition, it has two neat tricks up its sleeve.

First, you can incrementally hash strings:

var spark = new SparkMD5();
spark.append('Hi');
spark.append(' there');
var hexHash = spark.end();                    // hex hash
var rawHash = spark.end(true);                // OR raw hash

This is particularly handy for large strings, like what you might get using the FileReader API. Conveniently, Andre Cruz, the developer of SparkMD5, has included the code to do this in the GitHub README.

Second, it optionally supports Asynchronous Module Definition, which can reduce the initial load-time of pages and helps isolate your code from your markup. While AMD is certainly controversial, asynchronous loading of code does seem to be a prevailing trend.

TWSS: Naive Bayes Classifier and k-Nearest Neighbor library for NodeJS

Posted by Dave Mahon

TWSS is an acronym that stands for That’s What She Said, a joke frequently abused by the character Michael Scott on the US version of The Office. Why would anyone write a library that tells you whether or not "That’s what she said!" is an "appropriate" response to a given sentence? Frankly, I don’t know. However, during implementation, he created a generalized document NBC and k-NN tool that runs cleanly inside NodeJS.

In effect, with different training material, this is a powerful tool with an MIT license. Its also potentially very expandable.

So let’s see it in action.

Set the algorithm:

twss.algo = 'nbc';

Set the tolerance threshold:

twss.threshold = 0.5;
twss.is("You're hardly my first."); // false
 
twss.threshold = 0.3;
twss.is("You're hardly my first."); // true

Or, for your customized tool, return the probability:

twss.prob("The juice keeps coming out of the wrong hole!"); // 0.9961630818418142

How do we expand our algorithm selection? Look in /lib/twss.js:

var classify = {
  nbc: require('./classifier/nbc'),
  knn: require('./classifier/knn')
};

As you can see, adding algorithms is primarily a matter of a new file in the classifier subdirectory and adding a member element to the classify object. The new classifier must implement getTwssProbability() and isTwss().

However, you will have to lightly edit exports.probability() and exports.is() to recognize your custom algorithm.

UPDATE My apologies for the links to Wikipedia on the day of the SOPA blackout.

jQ.Mobi: Less compatible, but better performance

Posted by Dave Mahon

The plain reality is that the vast majority of mobile web traffic is on Android and iOS devices. BlackBerry users have, by and large, been so disappointed by the poor web experience out of the box that they tend not to go on the web. Windows smartphones are still a small slice of the mobile market, especially when you focus on 3G and LTE devices, which use the lion’s share of the traffic, at least until Nokia ramps up its smartphone production.

With that in mind, jQ.Mobi saw its first public release on Monday. Its developer, appMobi, calls it a beta.

The core engine and UI is 15KB gripped, which means that even when your user drops to EDGE, they’ll still have a good experience, since you still have 10KB leeway for images and markup. It is also optimized for simulating apps, including support for integration in tools like PhoneGap.

Further, it’s designed to make the interface as consistent as possible between Android and iOS devices, including fixed headers and footers and smooth CSS3 transitions. It’s not quite ready for tablet devices. If you watch the video, the interface during the Kindle Fire segment feels clunky, but they say they are working on tablet-optimized CSS.

In terms of syntax, jQuery users will feel at home. Still, be cautious with jQuery plugins, because while they should be run, many are still optimized for desktop environments and jQ.mobi is not intended for desktop use.

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.

Welcome Developers

Search for what you're looking for or take advantage of the Tools & Resources we’ve assembled to jump start your next project.

 
Tools & Resources