Category Archives: Web Development

O‚ÄôReilly Book “High Performance JavaScript” Now Available For Preorder

Last year, I was honored to be asked by Yahoo! engineer Nicholas Zakas whether I would be interested in contributing a chapter to an upcoming book about JavaScript performance. Well, after many months of hard labor by an impressive line up of talented engineers, this book, appropriately titled “High Performance JavaScript”, is now available for preorder on amazon.com (the book will be available on March 15th according to amazon). Here is the list of chapters:


A Better Implementation Of The Input Prompt Pattern

The Input Prompt pattern consists in prefilling a text field with a prompt as a way of supplying help information for controls whose purpose or format may not be immediately clear. In the browser, this pattern is most often implemented by dynamically modifying the value property of a text field element via the focus and blur event handlers attached to the text field, as shown in this example (live demo):

CSS:

.hint {
  color: #999;
}

Markup:

<input type="text" id="sbx">

JavaScript (based on YUI 3.0.0):

YUI().use('node', function (Y) {

    var sbx = Y.get('#sbx');

    Y.on('domready', function () {

        sbx.set('value', 'Search');
        sbx.addClass('hint');

        Y.on('focus', function () {
            if (this.get('value') === 'Search') {
                this.set('value', '');
                this.removeClass('hint');
            }
        }, sbx);

        Y.on('blur', function () {
            if (this.get('value') === '') {
                this.set('value', 'Search');
                this.addClass('hint');
            }
        }, sbx);

    });
});

Note: the code is intentionally implemented inside a domready event handler to work around issues related to form field caching.

The main problem with implementing this pattern using the value property is that the default text is used if the form is submitted while the input prompt is showing. Trying to work around this by testing the content of the text field when the form is submitted makes the default text impossible to use as a value. Another side effect of this implementation is that most developers will forget to attach a <label> element to the text field, leading to a confusing experience for screen reader users as they lack the necessary context to understand the purpose of the control.

A better implementation of this pattern consists in using a <label> element and positioning it on top of the text field it is attached to. Here is an example of this implementation (live demo):

CSS:

#container {
    position: relative;
}

#container label {
    position: absolute;
    top: 4px; *top: 6px; left: 3px;
    color: #999;
    cursor: text;
}

#container label.offscreen {
    left: -9999px;
}

Markup:

<div id="container">
    <label for="sbx" class="offscreen">Search</label>
    <input type="text" id="sbx">
</div>

JavaScript (based on YUI 3.0.0):

YUI().use('node', function (Y) {

    var sbx = Y.get('#sbx'),
        lbl = Y.get('#container label');

    Y.on('domready', function () {

        sbx.set('value', '');
        lbl.removeClass('offscreen');

        Y.on('mousedown', function () {
            setTimeout(function () {
                sbx.focus();
            }, 0);
        }, lbl);

        Y.on('focus', function () {
            lbl.addClass('offscreen');
        }, sbx);

        Y.on('blur', function () {
            if (sbx.get('value') === '') {
                sbx.set('value', '');
                lbl.removeClass('offscreen');
            }
        }, sbx);

    });
});

As always, I am looking forward to reading your comments and answering your questions in the comments section of this blog.

The YUI library source code is now hosted on GitHub

If you haven’t done so already, head over to the YUI Blog for the official announcement. I am proud to have made a (very modest) recent contribution to the library by porting the browser history utility to YUI3 (take a look at the source code) By the way, this new version of the browser history utility supports Opera and IE8 (in both quirks mode and IE7 standards mode) Moreover, it has more features than the YUI2 version, should be easier to use, and weighs a few hundred bytes less (after minification with the YUI Compressor) I’ll try to find some time in the next few weeks/months to write a bit more about YUI3 in general, and the new browser history utility and the YUI Compressor. Stay tuned!

YUI Compressor and Java Class Loader

The YUI Compressor uses a slightly modified version of the parser used in the Rhino JavaScript engine. The reason for modifying the parser came from the need to support JScript conditional comments, unescaped forward slashes in regular expressions — which all browsers support and many people use — and a few micro optimizations. The problem is that many users had the original Rhino Jar file somewhere on their system, either in their classpath, or in their JRE extension directory (<JRE_HOME>/lib/ext) This caused many headaches because the wrong classes were being loaded, leading to many weird bugs.

Today, I finally decided to do something about it. This meant writing a custom class loader to load the modified classes directly from the YUI Compressor Jar file. You can download the source and binary package here:

Download version 2.4 of the YUI Compressor

The skeleton of the custom class loader is pretty straightforward:

package com.yahoo.platform.yui.compressor;

public class JarClassLoader extends ClassLoader
{
    public Class loadClass(String name) throws ClassNotFoundException
    {
        // First check if the class is already loaded
        Class c = findLoadedClass(name);
        if (c == null) {
            // Try to load the class ourselves
            c = findClass(name);
        }

        if (c == null) {
            // Fall back to the system class loader
            c = ClassLoader.getSystemClassLoader().loadClass(name);
        }

        return c;
    }

    protected Class findClass(String name)
    {
        // Most of the heavy lifting takes place here
    }
}

The role of the findClass method is to first locate the YUI Compressor Jar file. To do that, we look in the classpath for a Jar file that contains the com.yahoo.platform.yui.compressor.JarClassLoader class:

private static String jarPath;

private static String getJarPath()
{
    if (jarPath != null) {
        return jarPath;
    }

    String classname = JarClassLoader.class.getName().replace('.', '/') + ".class";
    String classpath = System.getProperty("java.class.path");
    String classpaths[] = classpath.split(System.getProperty("path.separator"));
    for (int i = 0; i < classpaths.length; i++) {
        String path = classpaths[i];
        JarFile jarFile = new JarFile(path);
        JarEntry jarEntry = findJarEntry(jarFile, classname);
        if (jarEntry != null) {
            jarPath = path;
            break;
        }
    }

    return jarPath;
}

private static JarEntry findJarEntry(JarFile jarFile, String entryName)
{
    Enumeration entries = jarFile.entries();
    while (entries.hasMoreElements()) {
        JarEntry entry = (JarEntry) entries.nextElement();
        if (entry.getName().equals(entryName)) {
            return entry;
        }
    }
    return null;
}

Once we know where the YUI Compressor Jar file is, we can load the appropriate class from that file. Note the need to define the package the class belongs to before calling defineClass!

protected Class findClass(String name)
{
    Class c = null;
    String jarPath = getJarPath();
    if (jarPath != null) {
        JarFile jarFile = new JarFile(jarPath);
        c = loadClassData(jarFile, name);
    }
    return c;
}

private Class loadClassData(JarFile jarFile, String className)
{
    String entryName = className.replace('.', '/') + ".class";
    JarEntry jarEntry = findJarEntry(jarFile, entryName);
    if (jarEntry == null) {
        return null;
    }

    // Create the necessary package if needed...
    int index = className.lastIndexOf('.');
    if (index >= 0) {
        String packageName = className.substring(0, index);
        if (getPackage(packageName) == null) {
            definePackage(packageName, "", "", "", "", "", "", null);
        }
    }

    // Read the Jar File entry and define the class...
    InputStream is = jarFile.getInputStream(jarEntry);
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    copy(is, os);
    byte[] bytes = os.toByteArray();
    return defineClass(className, bytes, 0, bytes.length);
}

private void copy(InputStream in, OutputStream out)
{
    byte[] buf = new byte[1024];
    while (true) {
        int len = in.read(buf);
        if (len < 0) break;
        out.write(buf, 0, len);
    }
}

The last thing we need to do is bootstrap the application. In order to do that, we simply load the main class (YUICompressor) using our new custom class loader. All the classes that will be needed at runtime will use the same class loader:

package com.yahoo.platform.yui.compressor;

public class Bootstrap
{
    public static void main(String args[]) throws Exception
    {
        ClassLoader loader = new JarClassLoader();
        Thread.currentThread().setContextClassLoader(loader);
        Class c = loader.loadClass(YUICompressor.class.getName());
        Method main = c.getMethod("main", new Class[]{String[].class});
        main.invoke(null, new Object[]{args});
    }
}

As you can see, it's not terribly complicated to write a custom class loader. Note: I left out all the exception handling code and the import statements for clarity. The final code can be found in the downloadable archive. Cheers!

JavaScript: The Good Parts

JavaScript: The Good Parts (Book Cover)

Douglas Crockford just published his first book titled JavaScript: The Good Parts. After reading this book, some of you may be left with the impression that Douglas is always complaining about some aspect of this very popular programming language. However, having been a user of the JavaScript language for about 7 years, and having used it extensively in small web sites and large web applications, all I can tell you is that I could not agree more with the author.

It is really unfortunate that we live in an imperfect world. As such, there is no perfect programming language, and there will probably never be. However, by gaining a deep understanding of the philosophy and the inner workings of a programming language, and by sticking to a subset of that language (what the author refers to as the “good parts”), we can all become better programmers by constructing more reliable and more maintainable programs.

In JavaScript: The Good Parts, Douglas extensively describes that good subset of the JavaScript language, occasionally warning to avoid the bad. I consider Douglas’ book a must-buy for anybody who’s serious about developing professional applications for the web. It’s definitely well worth the read!

High Performance Ajax Applications – Video Presentation

Video snapshot

A few days ago, I gave a talk at Yahoo! about High Performance Ajax Applications. Eric Miraglia, from the YUI team, and Ricky Montalvo, from the Yahoo! Developer Network, were kind enough to shoot the video, edit it, and put it on the YUI Blog. In this talk, I cover the following topics:

  • Developing for high performance
  • High performance page load
  • High performance JavaScript
  • High performance DHTML
  • High performance layout and CSS
  • High performance Ajax
  • Performance measurement tools

Follow along by downloading the PowerPoint slides, or by looking at the slides on Slideshare. I’m looking forward to reading your comments and answering your questions in the comments section of this blog!