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

Entries Tagged as 'jQuery'

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.

jQuery Mobile 1.0 Final

Posted by Dave Mahon

The long anticipated jQuery Mobile library has hit version 1.0 Final. With support for most mobile devices, it facilitates rapid development of mobile friendly sites.

Note that it does require jQuery 1.6.4 and the jQuery Mobile 1.0 CSS file, in addition to the jQuery Mobile 1.0 JavaScript file. This means that pages that use it will very likely exceed the 25KB limit of some very old phones, preventing the page from loading at all on them. That said, most phones sold since 2008 do not have this limitation, so it shouldn’t hinder you too much. Still, focus on keeping image assets, JS, CSS and HTML as optimized as possible, because mobile performance is still pretty slow for most users.

Also, it does require a number of custom attributes, so you will want to explore their Getting Started documentation.

Gantt charts made easier, with ideas for improvements

Posted by Dave Mahon

Tait Brown has released an interesting jQuery extension for generating Gantt charts.

The most recent version adds support for local as well as JSON data sources and improves standard compliance while reducing the likelihood of CSS rule collisions.

One of the very first comments to the tumblr announcement was from jh asking, “Is it possible to represent dependencies among tasks?” This is an important Gantt chart feature, but not one that seems implemented – yet.

Using the live demo, I was able to inject a simple snippet between div.bar.ganttGreen and div.fn-label:
<div style="border-left: 1px solid #000; border-bottom: 1px solid #000; margin-top:-18px;height:30px; width:1px;"></div>

This produces a small black line to represent the relationship. While an arrow would be nicer, there is not enough space to represent it cleanly. I’m also using border-left and border-bottom so that it can eventually show relationships that don’t start and end at the same time.

Obviously, this is incomplete.

We will need to find a way to represent the relationship with another bar in the data. Each one is rendered by fillBars(), which simply iterates over the data property of the passed object, calling createProgressBar(). Presumably, we could add a parent property and use the array index of the parent bar as the value of parent.

We would still, however, need to calculate the relative positions of the bars, which will require a store of the row ID’s for each bar, so that we can test for visibility and horizontal and vertical positions.

These are not trivial changes, but they’re not insurmountable.

Hovercard – tooltips on steroids

Posted by Dave Mahon

Hovercard is a jQuery plugin that lets you hover what amounts to a tooltip. Except unlike your normal tooltip, this one supports event callbacks and lets you use arbitrary HTML and use as much space as you need.

They also provide support for Twitter and Facebook integration out of the box!

Suggested uses include virtual business cards, price comparisons and editing in place. Personally, my mind leaps to a web-based implementation of Civilization – it’s instant feedback on any cell in the world.

Check out their sample screenshot and imagine what you could do with it.
Hovercard Sample Screenshot

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.

jQuery UI fixes: z-index and modals

Posted by Dave Mahon

jQuery UI is useful, but several of its widgets suffer from an annoying bug by design. If you never deal with simulated modal windows then you’ll never even experience it, but if you try to use an autocomplete or datepicker widget within a simulated modal window, you’ll find the dynamically generated DIV’s behind the modal.

You might try hardcoding a very high z-index to compensate for this, but it’s not terribly flexible, especially within a complicated third-party template.

That is why I now use this snippet in the beforeShow (date picker) or open (autocomplete) events, acquired from sources I no longer recall, to fix it.

function(input, inst) {
  var zMax = 1;
  $(input).parents().each(function(){
    zMax = Math.max(zMax, $(this).css('z-index'));
  });

  setTimeout(
    function() {
      $('.ui-datepicker .ui-autocomplete').css('z-index', zMax + 1);
    },
    300
  );
}

Sadly, the use of setTimeout() is necessary, because the event fires before the markup is appended to the DOM. You may be able to cut it down to about 150 ms, but that can sometimes fail in IE on slow machines.

Creating Dynamic Styles with Handlebars.js and InsertRule

Posted by Don Albrecht

2 months ago, I wrote about InsertRule: a handy way to dynamically write style rules.  The problem is, building giant strings for complex CSS3 style rules is more than a little tedious to write and debug.  Today I’m going to discuss a method for streamlining this process using templates.

Step 1: Create a template for the CSS rule.

I’m using an html script tag for demonstration purposes.  In a  production setting you’ll want to precompile this.

    <script id="tab-template" type="text/x-handlebars-template">
        -webkit-border-top-left-radius: {{leftRadius}}px;
        -webkit-border-bottom-left-radius: {{leftRadius}}px;
        -moz-border-radius-topleft: {{leftRadius}}px;
        -moz-border-radius-bottomleft: {{leftRadius}}px;
        border-top-left-radius: {{leftRadius}}px;
        border-bottom-left-radius: {{leftRadius}}px;
        -webkit-border-top-left-radius: {{rightRadius}}px;
        -webkit-border-bottom-left-radius: {{rightRadius}}px;
        -moz-border-radius-topleft: {{rightRadius}}px;
        -moz-border-radius-bottomleft: {{rightRadius}}px;
        border-top-left-radius: {{rightRadius}}px;
        border-bottom-left-radius: {{rightRadius}}px;
        -moz-box-shadow: 0 0 5px #888;
        -webkit-box-shadow: 0 0 5px#888;
        box-shadow: 0 0 5px #888;
        
        width: 100px;
        border: 1px solid black;
        padding: 5px;
        background-color: #cecece;
</script>

Step 2: Define your custom attributes.

Handlebars takes an object as input to replace the dynamic variables in the template.  Here we’re specifying a large left radius and a right radius of 0.

var source   = $(“#tab-template”).html();
var tab_template = Handlebars.compile(source);
var rule =  tab_template( {leftRadius: 20, rightRadius: 10});

 

Step 3: Writing the Style

Use Style.Insert to attach the new rule, We’re using an ID here, but it could just as easily be any other selector.

 $.style.insertRule( ['#displaynode'], rule  );

You can learn more about InsertRule here:

InsertRule, A handy way to add CSS rules on the fly with jQuery

InsertRule, A handy way to add CSS rules on the fly with jQuery

Posted by Don Albrecht

I just stumbled across a great post on StackOverflow.  A contributed answered a question with a sweet plugin for dynamically creating CSS rules that apply page wide on the fly with javascript.

Here’s a simple example:

$.style.insertRule(['p','h1'], 'color:red;');
$.style.insertRule(['p'], 'text-decoration:line-through;'); 
$.style.insertRule(['div p'], 'text-decoration:none;color:blue');

Pretty sweet when you need to change styling on the fly, no?

You can view the original StackOverflow post here:

http://stackoverflow.com/questions/4232557/jquery-css-write-into-the-style-tag

The code is also cross posted to jsfiddle here:

http://jsfiddle.net/doktormolle/ubDDd/

Lettering.js A fun way to spice up Typography

Posted by Don Albrecht

CSS is awesome, but it lacks the ability to fine tune typography to the nth degree.  Want a spectacular drop cap, tighter kerning on a few letters, magical rainbow type?  You’re stuck with a bespoke and labor intensive solution.  Lettering.js can help alleviate those pains.

How it works, calling .lettering() on a text node, the node is broken up into a collection of spans uniquely classed for each letter.

For Example:  the HTML Node

<code><h1 class="fancy_title">Some Title</h1></code>

Can be transformed by

<code> $(document).ready(function() {    
 $(".fancy_title").lettering(); });</code>

And yields

<code><h1 class="fancy_title"> 
<span class="char1">S</span> 
<span class="char2">o</span>
 <span class="char3">m</span>
 <span class="char4">e</span> 
<span class="char5"></span> 
<span class="char6">T</span> 
<span class="char7">i</span> 
<span class="char8">t</span> 
<span class="char9">l</span> 
<span class="char10">e</span> </h1></code>

Now, you can style the code with css char# classes!

Check it out here:

http://daverupert.com/2010/09/lettering-js/