bitstorm.org

weblog of a webdeveloper

  1. Deferred and promise in jQuery

    Deferred and promise? What is this article about? Deferred and promise are part of jQuery since version 1.5 and they help in handling asynchronous functions like Ajax.

    Let's do a step back in time. A time without iPod or Xbox or Facebook. If you wanted to catch a mouseclick, you did it with element.onclick = someFunction; This became a problem when another part of the code also wanted to listen to this click. This was not possible, because you could only assign one function. This was solved at the time with the addEventListener DOM-function. With this, you can add as many listener functions as you want. Since then, that's the way we know how to do this.

    Now we have a similar problem with Ajax-calls. This time it's not the events, but the fact that Ajax supports only one callback function. Not only the jQuery $.ajax()-call, but also the underlying XMLHttpRequest-object.

    Promise

    Until jQuery 1.5, a typical $.ajax()-call looked like this:

    $.ajax({
      url: "/myServerScript",
      success: mySuccessFunction,
      error: myErrorFunction
    });

    The $.ajax()-call returns a jQuery XMLHttpRequest-object. Nothing new so far.

    Since version 1.5, the returned object implements the CommonJS Promises/A-interface. That's a mouth full. CommonJS is a initiative to define common and independent interfaces (API's). Promises/A is one such interface. The advantage is that these are not jQuery specific. For example, if you work with Node.js, there is a good chance you'll program with this same interface. That's good.

    The way of assigning callbacks with Promises is quite different:

    var promise = $.ajax({
      url: "/myServerScript"
    });
     
    promise.done(mySuccessFunction);
    promise.fail(myErrorFunction);

    “Okay, the interface has changed, so what's in it for me?”, you might ask.

    The advantages of promises are:

    1) You can call the done()- and fail()-functions more times, with different callbacks. Maybe you have a callback function that stops an animation, one that does a new Ajax-call and another function that shows the received data to the visitor.

    var promise = $.ajax({
      url: "/myServerScript"
    });
     
    promise.done(myStopAnimationFunction);
    promise.done(myOtherAjaxFunction);
    promise.done(myShowInfoFunction);
    promise.fail(myErrorFunction);

    2) Even after the Ajax-call has finished, you can still call the done()- and fail()-functions and the callbacks are executed immediately. So no messing around with variables holding different states. When a Ajax-call has finished, it will end up in either the success-state or the failed-state and this state will not change.

    3) You can combine promises. Sometimes you need to do two simultaneous Ajax-calls and you want to execute a function when both are successfully finished. To do this, you use the new $.when()-function:

    var promise1 = $.ajax("/myServerScript1");
    var promise2 = $.ajax("/myServerScript2");
     
    $.when(promise1, promise2).done(function(response1, response2){
      // Handle both responses
    });

    Deferred

    So what is a deferred and what is the difference with a promise? As you have seen above, a promise is an object that is returned from an asynchronous function. You need a deferred when you write such a function yourself.

    A deferred object can do the same as a promise object, but it has two functions to trigger the done()- and fail()-functions.

    A deferred object has a resolve()-functions for a successful result and to execute the functions assigned with done(). The reject()-function is for a failed result and executes the functions assigned with fail().

    You can give parameters to both the resolve()- and reject()-functions and they will be passed on to the functions registered with done() and fail().

    The promise object does not have resolve()- or reject()-functions. This is because you give the promise away to other scripts and you don't want them to resolve or reject the promise.

    Below is a simple script that illustrates how it works. The html is just an empty div with id "result".

    $('#result').html('waiting...');
     
    var promise = wait();
    promise.done(result);
     
    function result() {
      $('#result').html('done');
    }
     
    function wait() {
      var deferred = $.Deferred();
     
      setTimeout(function() {
        deferred.resolve();
      }, 2000);
     
      return deferred.promise();
    }

    You can also find this script on jsFiddle, so that you can experiment with it yourself.

    The wait()-function is the function returning a promise. This will be resolved with a setTimeout of two seconds. Instead of setTimeout, everything can be used that is asynchronous, like animations, Web workers etcetera. It should be clear that inside the wait()-function, we use the deferred object, but we return the limited promise-object.

    jQuery support

    On the jQuery blog, you can read that jQuery goes completely for promises and the old API with the error()-, success()- and complete()-functions will disappear eventually. When you use these functions, you might as well start rewriting them and use the promise-interface.

    Other possibilities

    This article is just an introduction to the deferred-object. jQuery supports even more functions. Look at the jQuery deferred documentatie voor all possibilities. It is, for example, possible to track the progress of a process.


    This article is originally posted in Dutch for the Fronteers Advent Calendar. Fronteers is the Dutch organisation of front end developers.

    Comments

  2. Are webdevelopers elitists?

    The last couple of days I was at the Fronteers conference in Amsterdam. These were amazing days.

    The Last speaker of the conference was Christian Heilmann. He had a very nice presentation telling front end developers to reach out to other user groups like Flash or Java user groups.

    I like Christian a lot and I also like his presentations a lot. But he said something I disagree with completely.

    He talked briefly about Muse, the code name of a new Wysiwyg HTML-editor from Adobe, which is still in beta. He criticized the bad HTML output it generates. And he wondered how such a big company could deliver such a bad product. Christian also said that people should just program plain HTML because it's so simple. And if it isn't simple enough, we should work to make it simpler.

    Creating a webpage for today's standards is absolutely not simple. Of course, creating a Geocities-like page is somewhat easy, but don't we agree almost all of them were really ugly? And we should make HTML and CSS simpler? Every new iteration adds more complexity and there are really no signs that will change.

    But Christian is not alone with his critique on Muse. When Adobe released the beta, a lot of blog posts, tweets and other remarks talked about how bad an idea it was. See for example the comments .Net magazine collected in Developers respond to Adobe Muse.

    What the hell? How is it possible we think like this? Have we become elitists? Is it because we're surrounded in our daily lives with the top 20% of the brightest people that we think creating webpages is easy? Can we really not see that writing HTML and CSS (let alone JavaScript) is very hard for the other 80% of the population? It really is. Why shouldn't the garage owner be able to make nice webpages? Or the soccer club? That is, without typing a letter HTML or CSS?

    So why does Muse has such a bad output? Well, how do big corporations like Adobe work? You're allowed to work for a couple of months on a new project and you'll better make a good demo for the management, otherwise your project gets killed. So you make sure the demo looks good, everything else can be fixed later. And I'm sure the people at Muse are smart enough to eventually make the editor create really nice HTML. Remember: this was only a beta.

    Eventually Muse might even created better HTML than a hand coder. Imagine adding a carrousel or accordion to the page and all WAI-ARIA attributes are automatically applied, so the carrousel or accordion is accessible by disabled people using a screen reader. Try to find a carrousel or accordion with proper WAI-ARIA attributes in current hand coded websites.

    I really think Adobe did the right thing with Muse and I look forward to the 1.0 release next year. It allows the other 80% to create their own webpages. Of course, some people will create crap, but others will create pages with beautiful animations that are almost impossible to code by hand.

    In the end, HTML, CSS and JavaScript is just technical stuff that sits between the author and the visitor, just like an engine between the driver and his trip or optics between the one making a photo and the photo itself. Techniques used shouldn't be relevant to the user.

    A world in which we can all participate, smart or not, is, in my opinion, a better world.

    Comments

  3. How to use the jQuery queue function

    Last week I was at a meeting of the JavaScript user group Amsterdam.js and Michiel Kalkman talked about the sequencer he wrote. The idea is very good: it let's you write loosely coupled software when using callbacks. Then I remembered jQuery has this same functionality build in.

    The problem

    If you've ever written code with a lot of callbacks, for example in a ajax-intensive website, it might have looked like this:

    function dothis {
    	// do something
    	someCallback( function() {
    		// do more
    	}); // etcetera
    });

    Maybe your code had even more levels of callbacks. This style of code is hard to understand, hard to change, hard to debug and hard to maintain.

    Turning every callback into a seperate, named function is a step in the right direction, but the different pieces are still very dependent on each other.

    The solution using queue

    One of the ways to write high quality code is to make your code loosely coupled. In the ideal situation, all callback functions are decoupled and don't know each others existance. With jQuery's queue function we can do exactly that. The code will look like this.

    $(someElement).queue(dothis).queue(dothat);
     
    function dothis(next) {
        // do something
        someCallback( function() {
            next();
        });
    }
     
    function dothat(next) {
        // do more
        next();
    }

    Now the functions are decoupled, so it's very easy to understand each function seperately, it's easy to replace a function and it's easy to refactor the code. In the first line, you can also easily see in which order which functions are called.

    This approach clearly had advantages, so what are the disadvantages? One (possibly the only one) is that you can't easily pass parameters this way. You could store the parameters somewhere using jQuery's data function or in a DOM data-* attribute.

    By default it uses the same queue that is used by the animate function, called 'fx'. If you don't want to interfere with animations, you can give your own, seperate queue name as the first parameter of the queue function.

    Example code using queue

    Of course I had to write an example to proof this really works. This example first fetches a feed url from the server, then it uses the Google Feed API to fetch and show the last feed item. Then, also with ajax, it lets the server calculate the MD5-hash of the article url, because this is needed in the last step, fetching and displaying tags assigned to this article using the Delicious API.

    See my jQuery queue example. Don't forget to look at the JavaScript source to see the queue function in practice.

    Comments

  4. Combat spam with SPF

    You might think: "combatting spam is all good and nice, but what has it to do with webdevelopment?". Well, many webdevelopers maintain internet domains and that's exactly where SPF takes place. SPF, which stands for Sender Policy Framework, is one of the better ways to get rid of spam.

    The idea behind SPF is simple: when an email is received, you can check whether the host sending the email is allowed to send an email coming from this email address. This works in two ways: first, a spam email send with your email address will be blocked and second, email that's really coming from you will not be marked as spam.

    So how can I make it work? First you have to collect all ip-addresses from which email is legitimately send. Usually it's just the address of the smtp server. If other servers like a webserver sends email and it's different from the smtp server, you might want to add its address as well. You also might want to explicitly block ip addresses. To block all (other) ip addresses, you can use "-all".

    You can prefix the following qualifiers to the addresses:

    + Pass Address is allowed. This is the default qualifier and can be omitted.
    - Fail Address is not allowed.
    ~ Softfail Use this to mark as not allowed during the transitioning process. The mail will be allowed but marked.
    ? Neutral Unknown whether it's allowed or not.

    Creating a simple DNS record

    To make clear the DNS record we are building is using SPF, we have to prefix the record with "v=spf1". So only allowing mail to be send from ip address 82.192.84.37 will give you this simple rule:

    v=spf1 ip4:82.192.84.37 ~all

    We start with ~all, so if we make a mistake, not all our mail will be marked as spam. If everything seems to work allright, we can change it to -all.

    Creating an SPF rule is one thing, adding it to the DNS is another. Usually you'll go the the control panel of your hosting provider, or, if you use a seperate DNS server, to the control panel of your DNS server. There should be an option to edit the DNS or the DNS zone. There you'll be able to add a DNS record.

    A DNS record consists of five fields. The first is the domain name. It can be "@" or your domain name with a "." at the end, like "bitstorm.org.". If you don't add the dot, it will be prepended to your hostname, so "www" will, in my case, become "www.bitstorm.org". But that's not the domain I use for my email, so I use "bitstorm.org.".

    The second field it the TTL (Time To Live) value, the time the value is valid. Usually it will be four hours or one day. The value is in seconds. Four hours is 14400 seconds and one day is 86400 seconds. The third field is always "IN" and the fourth field is "TXT", as a SPF record is a DNS text record.

    In the fifth and last field, we can enter the SPF rule. If you're using cPanel, you have to put the value between double quotes.

    bitstorm.org. 14400 IN TXT "v=spf1 ip4:82.192.84.37 -all"

    Save your changes and you're done.

    You'll probably want to check if everything is okay. If you have access to linux, you can use dig to view DNS records. To see the TXT records of bitstorm.org, you'll type "dig txt bitstorm.org".

    You can also use online tools like Geektools digtool to get DNS records.

    The best place to check is where it happens: with real email. All email programs can show you the headers of an email. A valid email address from my domain will pass:

    Received-SPF: pass (google.com: domain of edwin@bitstorm.org designates 85.17.71.92 as permitted sender) client-ip=85.17.71.92;
    Authentication-Results: mx.google.com; spf=pass (google.com: domain of edwin@bitstorm.org designates 85.17.71.92 as permitted sender) smtp.mail=edwin@bitstorm.org

    A spam email send from ip-address 186.8.36.165 will fail:

    Received-SPF: fail (google.com: domain of quensettaferrell@bitstorm.org does not designate 186.8.36.165 as permitted sender) client-ip=186.8.36.165;
    Authentication-Results: mx.google.com; spf=hardfail (google.com: domain of quensettaferrell@bitstorm.org does not designate 186.8.36.165 as permitted sender) smtp.mail=quensettaferrell@bitstorm.org

    You will see google.com in the header because Gmail is used.

    Including other ip-addresses

    If you're using Gmail to send email, then you have to add the ip addresses of Google too. But what happens if they change their ip-address, do you have to edit all your DNS entries?

    Fortunately, there is a solution for this. You can include the SPF records from other domains.

    For Gmail, you'll have to add include:_SPF.google.com to your SPF record:

    v=spf1 ip4:82.192.84.37 include:_SPF.google.com -all

    Other email service providers will have a similar mechanism.

    If you have a lot of ip addresses from which mail is send and a lot of domains, you don't want to edit all DNS entries of all your domains if one ip address changes. Just make your own _spf domain with a SPF record and include it in the SPF records of all other domains.

    These are the DNS records I'm using right now:

    _SPF 14400 IN TXT "v=SPF1 ip4:82.192.84.37 ip4:85.17.71.92 ip4:80.57.38.140 include:_SPF.google.com"
    bitstorm.org. 14400 IN TXT "v=SPF1 include:_SPF.bitstorm.org -all"

    What about Sender ID?

    Sender ID is developed by Microsoft and very similar to SPF. Although a Sender ID DNS record starts with "spf2.0...", it is not the successor of SPF. It even violates the SPF specification. You can read more about SPF vs Sender ID.

    Problems

    If you use email forwarding, SPF will fail and your email will be rejected. There are two solutions to this. One is to add the ip address of the domain the email is forwarded from to the SPF DNS record. The second solution is to encapsulate the email in another, email with another, allowed email address.

    More information

    If you want to know more about SPF, you can find lots of information on the Sender Policy Framework website.

    Besides all, ip4 and include, the SPF Record Syntax also supports a couple of other options. The full syntax can be read in the SPF Record Syntax.

    Comments

  5. HTML5 Game Jam

    Last week I participated in the HTML5 Game Jam, an initiative of SPIL games and Google. The contest was held in both SPIL games in Hilversum, a ten minute bike ride from my house, and simultaneously at Google’s office in downtown San Francisco. It started saturday at 10:00 am and ended sunday at 6:00 pm. Who wanted could stay during the night.

    The day started with a couple of talks by people experieced with html5 games. Then we had to form teams. I quickly formed a team with Peter van der Zee and Kornel (pornel). We decided to remake a classic from the eighties: Syndicate. Since we all knew our JavaScript and html5, but also were bad designers, we had a little problem. Design is a crucial part of a good game. I offered to do the design.

    While Kornel and Peter were working on the game engine, I made some characters and rockets with my best design I could, which isn't much. I spend most of the time creating isometric tiles. These could be used in the freeware Tiled Map Editor. I also wrote a JavaScript utility to convert the xml output of the editor to json, which could be used in the game. At around 3:00 am I went home for some sleep. Kornel and Peter kept working and slept a couple of hours at the SPIL office.

    At 3:00 pm we had to wrap up and with twelve other contestants, demo our game. One hour later, the winners were announced. It was quite exciting because many people who've looked at the game were impressed (especially when we turned on wave mode :-). We ended up third place. The winners were:

    1. MonkeyFortress by Tom Hastjarjanto
    2. Multi-player social tetris by Peter Nederlof and Jelle
    3. Enterprise by Pornel, Peter, Edwin

    Since it's a html5 contest, you have to open the pages in a modern browser. At this moment, the latest Safari or Chrome browsers work best.

    We could each pick a book or analog game from a stack.

    Here are some photo's people took at the event: Our team programming, giving the demo, another one giving the demo, our team with prices and the winner with his price, a Samsung Galaxy tablet.

    Peter also wrote about the event. The game is still in development, please take a look:

    Comments

  6. Fronteers conference 2010

    Just like the years before, the Fonteers conference 2010 was a success. It was held in the beautifull Tuschinsky theatre in Amsterdam. The event started the evening before with the Code Jam, a initiative of Koen Willems. The idea of the Jam was to have something interesting for everybody coming to Amsterdam a day before. People held short presentation about frontend related subjects. I held a presentation called "Swipe your site, enable touch interfaces". I showed with code and a demo how the touch interface works and how you could get smooth animations on a mobile device by using CSS transforms. Although more people came than expected, it was a very nice and informative evening.

    The next day the conference would start. As one of the organisers I had to be there at 7:00 o' clock. I was responsible for internet and WiFi and had to make sure the companies providing internet and WiFi could do their work. When the conference started, it quickly turned out using UMTS-boxes for internet didn't work that well. Fortunately, the venue, Tuschinsky, offered their own internet connection. From that moment the connection worked pretty well. Sometimes connections broke, but that could be solved by a simple reconnect.

    After one day of keeping an eye on the internetconnection, watching nice speakers, talking with others and at the end of the day having a nice dinner with nice people at Szmulewicz, I went home catching some sleep before day two started.

    Day two was just as nice as day one, except I had a head ache and didn't feel really well. This was probably caused by a combination of sleep deprivation, a hang over and a little bit of stress. At the end of the day I felt better and had a dinner with a couple of fellow organisers at Gaucho's.

    The line up of speakers was very nice and balanced. I missed the really in-dept talks we had in previous years. I'll try to make sure they return next year. I planned to write something about each speaker, but since Chris Heilmann and Stephen Hay did this already, there wasn't much for me to add. Except maybe for mentioning the talks I really enjoyed: css3 by css inventor Håkon Wium Lie, writing quality code by Jake Archibald and a feel good talk by Chris Heilmann.

    I also made some photos of the Fronteers conference.

    Every talk has been recorded. So keep an eye on the Fronteers website for the videos and slides of the speakers to appear or take a peek at Vimeo for the raw video's.

    Comments

  7. Introduction to the Google Closure Compiler

    Last year, on November 5th, Google released three JavaScript code libraries that are used in Google's impressive webapps like GMail and Google Maps. One part of the release is the Google Closure Library at which we'll take a closer look in this article.

    The Google Closure Library can do two things. First, it can optimize and minify your JavaScript code and second, it can do code checking.

    The big advantage of minifying your JavaScript code is that there's less to download so the page using it will appear faster. And since comments are removed, it allows you to write good documented code wihout being afraid it will make your code too big.

    Using the online Closure Compiler

    We start with some very simple JavaScript code:

    function showTotal(subtotal, shipping) {
    	var total = calculateTotal(subtotal, shipping);
    	showAmount(total);
    }
     
    function calculateTotal(total, shipping) {
    	return total+shipping;
    }
     
    function showAmount(total) {
    	document.getElementById("amount").innerHTML = "$ "+total;
    }
     
    showTotal(120, 30);

    We can use the online Closure Compiler to quickly see what the compiler does.

    The Closure Compiler has three levels of optimization. In the first level, it only removes white space like spaces, returns and tabs. This is the result:

    function showTotal(subtotal,shipping){var total=calculateTotal(subtotal,shipping);showAmount(total)}function calculateTotal(total,shipping){return total+shipping}function showAmount(total){document.getElementById("amount").innerHTML="$ "+total}showTotal(120,30);

    The second level is Simple optimization, in which local variable and function names are renamed to a shorter one.

    function showTotal(a,b){var c=calculateTotal(a,b);showAmount(c)}function calculateTotal(a,b){return a+b}
    function showAmount(a){document.getElementById("amount").innerHTML="$ "+a}showTotal(120,30);

    The third, Advanced level, it the most aggressive. The result is as follows:

    document.getElementById("amount").innerHTML="$ 150";

    That's impressive, isn't it?

    The Advanced level needs some extra work when your code is using external JavaScript code or when other code is calling your minified code.

    Take for example the following script, a very simple jQuery plugin:

    jQuery.fn.data = function(name) {
    	var first = $(this).eq(0);
    	if (first) {
    		return first.attr('data-'+name);
    	}
    }

    Compiled with Advanced level optimization, you get this:

    jQuery.c.data=function(b){var a=$(this).b(0);if(a)return a.a("data-"+b)};

    As you can see, the jQuery functions are shortened too. Ofcourse, this will not work. To fix this, we first have to make the Closure Compiler run on our local machine.

    Running the Closure Compiler locally

    Since the Closure Compiler is written in Java, we'll first make sure the Java Runtime Environment is installed. Then we can download the compiler-latest.zip and unzip it. To get an easy start, we put all files (data.js, compiler.jar and the batch/shell script below) in one directory.

    java -jar compiler.jar --js data.js --compilation_level ADVANCED_OPTIMIZATIONS --warning_level QUIET > data-min.js

    Running the batch/shell script without any changes will produce data-min.js with the same non functional code as with the online version above.

    Using externs

    To get functional code from the advanced level optimization, we have to supply the file containing the JavaScript that is called, in this case the jQuery source code. After copying jquery.min.js to the same directory, we can perform advanced level optimization. We only have to let the compiler know about the external JavaScript file with the --externs option:

    java -jar compiler.jar --js data.js --compilation_level ADVANCED_OPTIMIZATIONS --warning_level QUIET --externs jquery.min.js > data-min.js

    Now he output is what we want:

    jQuery.fn.data=function(b){var a=$(this).eq(0);if(a)return a.attr("data-"+b)};

    With the --externs option, you have to add all files your code is calling.

    External references

    The --externs option only works for JavaScript files your code is calling. If your code is called from another JavaScript file or even from a HTML-document or you just want to provide an API, things are a bit harder.

    Assume you have this function and you want to minimize it:

    function getData(element, name) {
    	return element.getAttribute('data-'+name);
    }

    If you optimize this with advanced level optimization, you get an empty file. The compiler "sees" that the function is never called and thinks the function can be removed.

    There are couple of ways to solve this.

    1. The way Google suggests: attach the function to the global window object like this:

    function getData(element, name) {
    	return element.getAttribute('data-'+name);
    }
    window['getData'] = getData;

    Minified, it becomes:

    function a(b,c){return b.getAttribute("data-"+c)}window.getData=a;

    Personally, I think adding every function to the window object is very ugly. First, you pollute your own code just to get it compressed and second, you are adding code which doesn't help the minification.

    2. A better way is to use a namespace. This is a better practice anyway and prevents name collisions. Now you only have to add the namespace to the global window object. This is also what jQuery does. In JavaScript, there are many ways to create a namespace.

    If jQuery would only contain the function above, it would look like this (simplified):

    (function() {
    	var jQuery = {};
    	jQuery.getData = function(element, name) {
    		return element.getAttribute('data-'+name);
    	}
    	window['jQuery'] = jQuery;
    })();

    The resulting code is:

    (function(){var a={};a.getData=function(b,c){return b.getAttribute("data-"+c)};window.jQuery=a})();

    3. The last way is to not provide any API at all. You could just merge all you JavaScript code into one single minified file. It's easy and minifies very well. The Closure Compiler accepts multiple files with multiple --js parameters:

    java -jar compiler.jar --js data.js --js mylib.js --js jquery-min.js --compilation_level ADVANCED_OPTIMIZATIONS --warning_level QUIET > all-min.js

    Annotations

    The Google Closure Compiler can do more than only minifying. It can also do type checking. You thought type checking is not possible in JavaScript? Well, now it is. With the Closure Compiler you can annotate the types of variables and signatures of functions in comments. These comments look just like the comments used in JSDoc, so you can generate documentation with it, too.

    With annotations you effectively turn JavaScript into a strongly typed language and prevent a common source of errors from happening.

    The function we used earlier can now be written as:

    /**
    * @param {!Element} element
    * @param {string} name
    * @return {string}
    */
    function getData(element, name) {
    	return element.getAttribute('data-'+name);
    }

    The two arguments have the types Element and string and the return type is also string. The exclamation mark in front of Element means the Element object can't have the null value. So what happens if you call the annotated function with the wrong parameters? Let's call getData like this:

    getData('body', 'size');

    The error output you get after running the Closure Compiler is:

    C:\Users\Edwin\Desktop\Closure Compiler Tests\cc-bat\typing.js:10: WARNING - actual parameter 1 of getData does not match formal parameter
    found : string
    required: Element
    0 error(s), 1 warning(s), 100,0% typed

    A long, nicely documented list of all possible annotations can be found in the Annotating JavaScript documentation. The Closure Compiler has type information for the most common JavaScript functions, including, for example, the W3C DOM bindings. In the externs part of the source code, you'll find the whole list.

    There are no build in extern files for common JavaScript libraries, so you have to search for one or create one yourself. There is a contrib directory in the Closure Compiler source code where you can find a couple of contributed extern files. One of them being a extern file for jQuery.

    Using externs only work when the warning level is set to VERBOSE. So an example batch/script file using typed externs is:

    java -jar compiler.jar --js data.js --externs jquery.externs.js --compilation_level ADVANCED_OPTIMIZATIONS --warning_level VERBOSE > data-min.js

    Even is you're not going to use the type checking feature, you should at least know about the @license or @preserve annotation. They both do the same thing: preserve the comment. This is very handy for copyright and license information.

    Windows users might be interested in a small script I wrote to minify a JavaScript file by just dragging it to this script. It already includes the Closure Compiler. Download compile-wsf.zip.

    Do you want more information? You can read more about the Google Closure Compiler on Google Code.

    Comments

  8. Report of the Dutch PHP Conference 2010

    For the third time, I visited the Dutch PHP Conference. Just as before, it was held in the RAI Convention Centre in Amsterdam. And as before, this two-day conference took place on Friday and Saturday. I always wonder why it's Friday and Saturday. Is it that if your employer or school doesn't let you go on Friday, you can at least go on Saturday? Or if your employer does let you go, you can trade in your work day, but you don't have to trade in your free Saturday? Being a free lancer, it's not really an issue for me, so I went both days.

    The conference has three tracks, so planning which presentations to see is a task on itself. There was also an unconference-track. Because during the whole conference there was always something interesting in the regular tracks and because you never know what the quality of the unconference-track will be, I didn't visit any unconference-track.

    Friday

    The conference started with a keynote from Kevlin Henney, editor of 97 Things Every Programmer Should Know. This book contains little pieces of wisdom written by different programmers. Kevlin took a couple of them and explained them. For example how to make estimates, how to have code reviews, why you shouldn't change code on the production server, why you should test, etcetera. Very informative, especially if you haven't already learned it the hard way.

    The first talk in a track was Designing for Reusability by PHP-contributor and XDebug-developer Derick Rethans. He talked about how to prevent hard dependencies, why singletons are bad for testing, the problems of ActveRecord and why traits will be a solution. Very intersting talk.

    The second talk was The Cake Is A Lie by Sebastian Bergmann. It was not a talk about how bad CakePHP is, but more a opinion about how bad generated code is. I couldn't really relate to his problems. I've worked on a large project in which the ORM-code was generated. In this project, we didn't change the generated code but instead we inherited from it and it was nice to work with. Sebastian did not present any alternatives.

    I was a bit dissapointed by The Art of Scalability, a talk from Lorenzo Alberton, and I think I was not the only one. He didn't talk about scalability from a technical point of view, but from a management point of view.

    In Under PHP's hood, Johannes Schlüter talked about the inner workings of PHP. He explained how the Zend engine and PHP Core are seperate things. He explained the difference between include and require and the -_once-variants. He also explained how references work and why you should keep having references to a minimum. He also showed how it can even hurt performance.

    Although I've never used GIT, I thought visiting Advanced Git from David Soria Parra might be interesting anyway. He adviced to make a branch for every task you do. And only rebase local branches, never pulled or pushed branches. I don't know what pulled or pushed branches are, but when I'm start using GIT, I know this tip :-) He said GIT doesn't work well on Windows because FAT doesn't support symlinks and execute-bits. Huh? Which Windows-user still uses FAT, except from portable storage? A strange assertion, I think.

    The talk Crash, Burn, Recover! from from Cal Evans showed Flex using Flash Builder. He build a recipe search app from scratch. Well, at some point it didn't work and he had to revert to a prepared app. He showed the power of Flash Builder and how you can build a program in one hour. The result can be deployed as a Flash swf-file or a AIR application. It was nice to see how Flex works.

    I didn't go to the DPC Conference Social that evening (with free beer!). Maybe next year.

    Saturday

    The second day started off with Security-Centered Design: Exploring the Impact of Human Behavior by Chris Shiflett. He showed, nicely illustrated, how humans are sensitive to certain kind of security attacks. He explained Ambient signifiers: how you can subconsciously direct your users. For example, in Tokyo they introduced different kinds of background music in the subway, depending on where you are. It turned out that as a result, many more people didn't forget to leave the train on time, resulting in a more profitable subway system (and, of course, happier customers). He showed the movie Person Swap and the Colour changing card trick, which shows how easy it is to deceive people. He also explained the Twitter Clickjacking Hack. Although it didn't really had much to do with PHP, it was a very good presentation.

    The next talk I visited was Async webservices with php and node.js by Sebastian Schürmann. He showed how asynchronous calls can improve performance and how it is done in PHP, compared to Node.js. He showed an example in PHP with Curl and an example in Node.js. The Node.js-example was much cleaner and easier. Other asynchronous API's in PHP are the Streams API and MySQLnd. He did a call to the developers of PHP to make asynchronous programming in PHP as easy as in Node.js.

    In the talk APC & Memcache the High Performance Duo, Ilia Alshanetsky explained how APC works and how you can use it as a persistent key-value store. He also compared it to Memcache and explained what the differences are. He also explained the advantages and disadvantages of igbinary: it's much faster and smaller, but not interchangeable with other languages. For me this was the most interesting and informative talk of this conference.

    After the lunch Ian Barber had a talk about local search engines: In Search Of... Integrating Site Search. He showed the pros and cons about the most popular onces: sphinx, swish-e, lucene, solr and xapian. He also showed the importance of a good stemmer.

    The last talk I visited was Plant Pyrus in your system - A guide to a plugin system by Helgi Þormar Þorbjörnsson. He explained how hard it is to develop your own plugin system which has to deal with dependencies. He worked on Pyrus, which you can integrate in your own software and should also become part of PEAR.

    The conference ended with a panel discussion about the future of PHP.

    Just like the years before, it was a very interesting conference with something for everybody. I'm quite sure I'll be there again next year.

    Comments

  9. Animate anything in jQuery

    I've been using jQuery for three years now in several projects and I love it. One of the many reasons I like jQuery is its extensibility. It's very easy to write your own plugin, your own CSS pseudo selector-like filter or your own easing function.

    What's less known is that you can also customize the animate function. Every jQuery-user knows you can animate all number-based CSS-properties. (Did you know you can also animate scrollTop and scrollLeft?) In this article I explain how to customize the animate function.

    Customizing the animation-function is not so hard and gives you a couple of features for free: think about the fx-queue, easing, callbacks and setting the duration.

    The first thing I wanted to animate was fading one color to another. It turned out John Resig himself already wrote a plugin to does just that: Color Animations.

    Unfortunately, it has a bug which makes the plugin unreliable. To initialize the animation, the plugin checks for fx.state being zero. I turned out that with consecutive calls, the animation can start without fx.state being zero and as a result, the animation not performing.

    My next quest was to rewrite the plugin to my liking. I fixed the bug. I added the missing borderColor, so to change the border color, it's not longer necessary to specify all four borders seperately. I also tried to keep the plugin very small.

    Take a look at the result: the Color animation jQuery-plugin.

    So how can you make your own custom animation? Just like the other jQuery-customizations, it's actually quite simple. Take for example the code to animate the background color:

    $.fx.step.backgroundColor = function(fx) {
    	if (!fx.init) {
    		fx.begin = parseColor($(fx.elem).css('backgroundColor'));
    		fx.end = parseColor(fx.end);
    		fx.init = true;
    	}
    	fx.elem.style.backgroundColor = calculateColor(fx.begin, fx.end, fx.pos);
    }

    Give $.fx.step a new property and assign it a function which will handle the animation. This function has one argument, say fx, which belongs to that one animation, so you can use it anyway you like. It has some properties already set. The most important are fx.elem, fx.end and fx.pos. In fx.elem you'll find the element on which the animation is applied, and in fx.end you'll find the end-value you want to animate to. fx.pos is a float, going form zero to one during the animation.

    In the example above, some initialization is done at the first call of the function in an animation. Here, the begin and end values are calculated. The rest of the functions assigns the calculated value to the CSS-property of the element. The calculation looks like this:

    begin + pos * (end - begin)

    If the animation is called with the end-value being a string, then fx.end will be that string. So when calling a.animate({color: "#ccc"}), fx.end will be "#ccc". However, if the string starts with a number then fx.end becomes that number. So when calling a.animate({myProp: "10px 20px"}), fx.end will be 10 and you'll lose the rest of the string. To get the whole string you should look at fx.options.curAnim.myProp instead of fx.end. In this last example, myProp is a self defined property.

    I thought a cool thing to animate is the new shadow CSS-property. A box shadow property consists of several parts: the color, whether it is inset, the x- and y-offset, the blur-radius and the spread-radius. All of these had to be taken into account when writing the plugin.

    The result is the Shadow animation jQuery-plugin.

    Unfortunately, this plugin does not work in Opera and Internet Explorer. Opera has a strange bug in which you can't request the current shadow-value. Internet Explorer is miles behind and doesn't support CSS-shadows. I expect the plugin will work in Internet Explorer 9.

    These two animation plugins are the first on my list of jQuery-plugins. It's my intention more will follow.

    Update: a couple of months after this article was published, jQuery 1.4.3 was released, with better support for writing custom CSS-properties and animations. Read more about this technique called jQuery.cssHooks.

    Comments

  10. Faster websites with gzip compression

    One of the best ways to improve the user experience of a website is to make sure it loads fast. In a test done by Mozilla, it also improves conversion. Research by Google also shows advantages.

    One of the easiest ways to improve download speed is using gzip. Since many webbased files like html, css and javascript are text based, compressing them with gzip will result in more than 50% size reduction.

    Older browsers had some problems with gzip, so site owners where a bit reluctant to use gzip. Currently, all modern browers (even IE with the right service pack applied) have no problem with using gzip.

    Apache has a module called mod_deflate, which is easy to enable. For example:

    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript text/css

    Mod_deflate will compress the content on the fly for every request. On a high-performance site, that's not really what you want. There are better ways.

    Compressing static content

    First you have to compress all text files. Typically, there are files ending with .html, .css, .js and .xml. When using Linux, make sure you have gzip installed. Don't just gzip the files you want to compress, because the original file will be gone. Better is to do this:

    gzip -nc myfile.css >  myfile.css.gz

    Disadvantage is, you can't do this with a bunch of files. I wrote a little script to fix this:

    echo -n $@ | xargs -d ' ' -I '{}' sh -c "gzip -n -c {} > {}.gz"

    Put it in a file, for example /usr/local/bin/zipit, make it executable: chmod +x /usr/local/bin/zipit and now you can use it to compress single files, but also files with wildcards. For example:

    zipit *.js *.css

    If you had lib.js and style.css, now you will also have the compressed versions: lib.js.gz and style.css.gz.

    Warning: you have to be careful here: uploading a new .js- or .css-file won't work! You have to run zipit again, otherwise the .gz-file with the old content might be picked up.

    In Windows, you can gzip your files in a batchfile. You can use the free 7-Zip to to that. For example:

    "C:\Program Files\7-Zip\7z.exe" a -tgzip style.css.gz style.css

    Let Apache serve compressed content

    There are several ways to let Apache serve the .gz-files. I prefer using mod_rewrite. I wrote the following configuration file to serve the gzipped files:

    <FilesMatch "\.html\.gz$">
      ForceType text/html
      Header set Content-Encoding: gzip
    </FilesMatch>

    <FilesMatch "\.js\.gz$">
      ForceType text/javascript
      Header set Content-Encoding: gzip
    </FilesMatch>

    <FilesMatch "\.css\.gz$">
      ForceType text/css
      Header set Content-Encoding: gzip
    </FilesMatch>

    RewriteEngine On
    ReWriteCond %{HTTP:accept-encoding} gzip
    ReWriteCond %{REQUEST_FILENAME} !\.gz$
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.gz -f
    RewriteRule ^(.+\.js|.+\.css|.+\.html)$ $1.gz [L]

    It's quite low-level and therefore very clear. The rewrite rules checks the browser supports gzip, then it makes sure it's not already getting the .gz-file. As a last check it checks for the existance of the .gz-file. If that's the case, the url is rewritten to have .gz at the end. The FilesMatch-directive makes sure the content-type is correct and adds "Content-Encoding: gzip" to the http-header, so the browser knows it's gzipped content.

    Gzip and PHP

    Most server-side languages also support gzipped output. PHP has several ways to do that.

    If you're using ob_start to buffer the output, you can easily enable gzip-compression by using ob_gzhandler:

    ob_start("ob_gzhandler");

    A better way might be to enable gzip on all PHP-scripts. Just enable zlib.output_compression in your php.ini-file:

    zlib.output_compression On

    PHP has quite a lot of gzip-related functions. You can easily zip or unzip strings and work with gzipped files as they where normal files.

    Check gzip is working

    How can you be sure your content is compressed? Just open the Net-tab within Firebug and reload the page. Open the headers of the file you want to inspect. It will look similar to this:

    Date                Mon, 10 May 2010 14:19:06 GMT
    Server              Apache/2.2.4
    Vary                accept-encoding
    Last-Modified       Thu, 29 Apr 2010 09:23:59 GMT
    Etag                "9043e7-856-afc129c0"
    Accept-Ranges       bytes
    Content-Length      2134
    Cache-Control       max-age=172800 proxy-revalidate
    Content-Encoding    gzip
    Content-Type        text/html

    When you see "Content-Encoding gzip" as in the example above, you'll know it is compressed. Or use YSlow or Page Speed and look at the A's you'll get!

    Comments

<>