Kwissle

My real-time quiz battle game Kwissle.com

Crosstips.org

My fun Crossword solver project. Crosstips.org & Krysstips.se

Kung Fu

Fujian White Crane Kung Fu

Photos

Photoalbum, both old and new.

Twitter

Follow me on Twitter

Contact me

My contact details and how to contact me.

 

KungFuPeople.com
Do you train Kung Fu?
Or know someone who does?
Then check out KungFuPeople.com


Mobile version of this page Mobile version of this page

RSS

Hot topics

by Anderson Pierre Cardoso: Thanks =]. I'm definitely going to use it. Great post, thanks again!...

Integrate BrowserID in a Tornado web app

by : Pretty cool app! BTW I'm working now on my own first web app: http://www.fi...

My first iPhone web app - Crosstips iPhone interfa

by Jonathan: I had a similar issue with setAttribute not working on IE. I put it in a t...

setAttribute('style', ...) workaround for IE

by terrence: The simpsons are from Ohio. Check the Halloween special #5 or #6. The one w...

Ask Yahoo "What state do the Simpsons live in?"

by terrence: The simpsons are from Ohio. In the Halloween episode where the giant ads c...

Ask Yahoo "What state do the Simpsons live in?"

by Ashraf at Akbar: Hi Thanks for help...

Lost my mobile phone

by selevistar: verey good...

fcgi vs. gunicorn vs. uWSGI

by scott: the simpsons live in florida because in the simpson hit and run buy marges ...

Ask Yahoo "What state do the Simpsons live in?"

Old entries


July, 2011
A blog comment spam solution: Retalition!
A taste of the Django on inside Mozilla, Sheriffs Duty
Comparing Google Closure with UglifyJS
Slides about Kwissle from yesterdays London Python Dojo

June, 2011
Chinese tea sampler pack now on sale
Optimization story involving something silly I call "dict+"
Launching Kwissle.com
Google teething problems still with duplicated content
Test static resources in Django tests

2011
2010
2009
2008
2007
2006
2005
2004
2003

 

You're viewing blogs from JavaScript only. RSS?

View all different categories

13th of October

Web developmentJavaScript

Going real simple on HTML5 audio

DoneCal users are to 80+% Chrome and Firefox users. Both Firefox and Chrome support the HTML <audio> element without any weird plugins and they both support the Ogg Vorbis (.ogg) file format. change log here

So, I used use the rather enterprisey plugin called SoundManager2 which attempts to abstract away all hacks into one single API. It uses a mix of browser sniffing, HTML5 and Flash. Although very promising, it is quite cumbersome. It doesn't work flawlessly despite their hard efforts. Unfortunately, using it also means a 30kb (optimized) Javascript file and a 3kb .swf file (if needed). So, instead of worrying about my very few Internet Explorer users I decided to go really dumb and simple on this.

The solution basically looks like this:

 // somewhere.js
 var SOUND_URLS = {
   foo: 'path/to/foo.ogg',
   egg: 'path/to/egg.ogg'
 };

 // play-sounds.js

 /* Call to create and partially download the audo element.
  * You can all this as much as you like. */

 function preload_sound(key) {
  var id = 'sound-' + key;
  if (!document.getElementById(id)) {
    if (!SOUND_URLS[key]) {
      throw "Sound for '" + key + "' not defined";
    } else if (SOUND_URLS[key].search(/\.ogg/i) == -1) {
      throw "Sound for '" + key + "' must be .ogg URL";
    }
    var a = document.createElement('audio');
    a.setAttribute('id', id);
    a.setAttribute('src', SOUND_URLS[key]);
    document.body.appendChild(a);
  }
  return id;
 }

 function play_sound(key) {
   document.getElementById(preload_sound(key)).play();
 }

 // elsewhere.js
 $.lightbox.open({
    onComplete: function() {
       preload_sound('foo');
    }
 });
 $('#lightbox button').click(function() {
    play_sound('foo');
 });

Basically, only Firefox, Chrome and Opera support .ogg but it's a good and open source encoding so I don't mind being a bit of an asshole about it. This little script could be slightly extended with some browser sniffing to work with Safari people but right now it doesn't feel like it's worth the effort.

This make me happy and I feel lean and light. A good feeling!

22nd of August

JavaScript

Title - a javascript snippet to control the document title

This is a piece of Javascript code I use on Kwissle to make the document title change temporarily. Other people might find it useful too.

Code looks like this:

 var Title = (function() {
  var current_title = document.title
    , timer;

  return {
     showTemporarily: function (msg, msec) {
       msec = typeof(msec) !== 'undefined' ? msec : 3000;
       if (msec < 100) msec *= 1000;
       if (timer) {
         clearTimeout(timer);
       }
       document.title = msg;
       timer = setTimeout(function() {
         document.title = current_title;
       }, msec);
     }
  }
 })();

Demo here

10th of July

JavaScript

Comparing Google Closure with UglifyJS

On Kwissle I'm using Google Closure Compiler to minify all Javascript files. It's fine but because it's java and because I'm running this on a struggling EC2 micro instance the CPU goes up to 99% for about 10 seconds when it does the closure compilation. Sucks!

So, I threw UglifyJS into the mix and instead of replacing the Closure compiler I added it so it runs alongside but I obviously only keep one of the outputs.

Here is the log output when I run it on my MacbookPro:

 MAKING ./static/js/account.js
 UglifyJS took 0.0866 seconds to compress 3066 bytes into 1304 (42.5%)
 Closure took 1.2365 seconds to compress 3066 bytes into 1225 (40.0%)
 MAKING ./static/js/ext/jquery.cookie.js
 UglifyJS took 0.0843 seconds to compress 3655 bytes into 3009 (82.3%)
 Closure took 1.3472 seconds to compress 3655 bytes into 4086 (111.8%)
 MAKING ./static/js/ext/jquery.tipsy.js
 UglifyJS took 0.1029 seconds to compress 7527 bytes into 3581 (47.6%)
 Closure took 1.3062 seconds to compress 7527 bytes into 3425 (45.5%)
 MAKING ./static/js/maxlength_countdown.js
 UglifyJS took 0.082 seconds to compress 1502 bytes into 1033 (68.8%)
 Closure took 1.2159 seconds to compress 1502 bytes into 853 (56.8%)
 MAKING ./static/js/ext/socket.io-0.6.3.js
 UglifyJS took 0.299 seconds to compress 76870 bytes into 30787 (40.1%)
 Closure took 2.4817 seconds to compress 76870 bytes into 30628 (39.8%)
 MAKING ./static/js/scoreboard.js
 UglifyJS took 0.084 seconds to compress 2768 bytes into 1239 (44.8%)
 Closure took 1.2512 seconds to compress 2768 bytes into 1167 (42.2%)
 MAKING ./static/js/rumbler.js
 UglifyJS took 0.0872 seconds to compress 3087 bytes into 1384 (44.8%)
 Closure took 1.2587 seconds to compress 3087 bytes into 1235 (40.0%)
 MAKING ./static/js/ext/shortcut.js
 UglifyJS took 0.0987 seconds to compress 5796 bytes into 2537 (43.8%)
 Closure took 1.3231 seconds to compress 5796 bytes into 2410 (41.6%)
 MAKING ./static/js/play.js
 UglifyJS took 0.1483 seconds to compress 18473 bytes into 10592 (57.3%)
 Closure took 1.4497 seconds to compress 18473 bytes into 10703 (57.9%)
 MAKING ./static/js/playsound.js
 UglifyJS took 0.0824 seconds to compress 1205 bytes into 869 (72.1%)
 Closure took 1.2335 seconds to compress 1205 bytes into 873 (72.4%)  

(Note here that for the file ./static/js/ext/jquery.cookie.js Closure failed and when it fails it leaves the code as is and prepends it with a copy about the error from the stdout. that's why it's greater than 100% on that file)

Here are the averages of those numbers:

 AVERAGE TIME: (lower is better)
   * UglifyJS: 0.11554 seconds
   * Closure: 1.41037 seconds

 AVERAGE REDUCTION: (higher is better)
   * UglifyJS: 45.6% 
   * Closure: 51.5%

(I'm skipping the file that Closure failed to minify)

So, what does that mean in bytes? These are the source Javascript files for two pages but the total is 123949.0 bytes. With Closure that saves me 63833.7 bytes (62 kbytes) whereas UglifyJS only saves me 57760.2 bytes (56 kbytes) of bandwidth.

Discussion...

The fact that Closure fails on one file is a real bummer. I'm not even using the advanced options here.

UglifyJS doesn't save as many bytes as Closure does. This is potentially important because after all, minification process happens only once per revision of the original file but might be served hundreds or millions of times.

Because I run my minifications on-the-fly it does matter to me that UglifyJS is 1220% faster.

It's rare but I have observed twice that the minified Javascript from Closure has actually broken my code. I default to suspect that's my fault for not making the code "minifyable" enough (e.g. too many global variables).

I've just noticed that I'm relying on files that almost never change (e.g. jquery.tipsy.js). I might as well create a ...min.js versions of them and add them to the repository.

In conclusion...

Because of the convenience of UglifyJS being so much faster and that it doesn't choke on that jquery.cookie.js file I'm going switch to UglifyJS for the moment. The remaining bytes that I don't save become insignificant if you add the gzip effect and compared to images the bandwidth total is quite insignificant.

9th of May

JavaScript

A script tag's type in HTML5

If you look at html5boilerplate.com they never use any type on their <script> tags. Hmm... but is there more to it?

If you don't specify a type, the default becomes "text/javascript" but according to RFC4329 the "text/javascript" MIME type is obsolete in favor of "application/javascript".

If the default MIME type for a <script> tag thus becomes either "text/javascript" or "application/javascript" is there any sensible browser on this green earth that would not translate a piece of inline Javascript code as, exactly that; Javascript? Probably not.

What about <script> tags with a src attribute? Does the type matter?

I read the spec a couple of times and it feels like reading legalese but it ultimately says: the value of the type tag must be that of the body of the script tag.

So, what happens if you embed a javascript file with a mismatching type? Let's see:


> Read the whole text (200 more words)

1st of May

JavaScript

maxlength_countdown() - a useful jQuery plugin for showing characters left

If people find this useful I might turn it into a proper jQuery plugin and publish it.

Without further ado; here's the demo

What it does is that for all input fields that have a maxlength="nnn" it shows a counter to the right that increases in opacity as it reaches the maximum. You can generally start it like this:

 $('input[maxlength]').maxlength_countdown();

Since the plugin "hard codes" the count down expression in English you can override it easily like this:

 $('input[name="message"]').maxlength_countdown(function (count, max) {
    return count + " (max: " + max + ")";
 });

What do you think? Is it useful? Does it make sense?

14th of April

JavaScriptMongoDB

Mocking DBRefs in Mongoose and nodeunit

Because this took me a long time to figure out I thought I'd share it with people in case other people get stuck on the same problem.

The problem is that Mongoose doesn't support DBRefs. A DBRef is just a little sub structure with a two keys: $ref and $id where $id is an ObjectId instance. Here's what it might look like on the mongodb shell:

 > db.questions.findOne();
 {
        "_id" : ObjectId("4d64322a6da68156b8000001"),
        "author" : {
                "$ref" : "users",
                "$id" : ObjectId("4d584fb86da681668b000000")
        },
        "text" : "Foo?",
        ...
        "answer" : "Bar"
        "genre" : {
                "$ref" : "question_genres",
                "$id" : ObjectId("4d64322a6da68156b8000000")
        }
 }

DBRefs are very convenient because various wrappers on drivers can do automatic cross-fetching based on this. For example, with MongoKit I can do this:

 for question in db.Question.find():
    print question.author.first_name

If we didn't have DBRefs you'd have to do this:

 for question in db.Question.find():
    author = db.Authors.findOne({'_id': question.author})
    print author.first_name


> Read the whole text (420 more words)

16th of March

JavaScript

QUnit testing my jQuery Mobile site in full swing

QUnit testing my jQuery Mobile site in full swing Yay! I've figured out how to properly unit tests my jQuery Mobile app that I'm working on. This app uses localStorage, localSession, lots of AJAX and works both offline and online. Through various hacks and tricks I've managed to mock things so that I can easily test the otherwise asynchronous AJAX calls and I can also test the little quirks of jQuery Mobile such as re-rendering <ul> tags after having changed the DOM tree.

I'm using the QUnit testing framework and I like it. The app isn't launched yet and the code is currently protected but once I get it nailed a bit more I'll blog about it more fully so other people can jump in unit testing their Javascript heavy jQuery Mobile sites too. For now I'm up to 75 tests and it's growing steadily.

Here's a little taster for how I mock the $.mobile, AJAX and the localStorage stuff:

 module("Storage and AJAX", {
   setup: function() {
      localStorage.clear();
   },
   teardown: function() {
      localStorage.clear();
   }
 });

 var MockMobile = function() {
   this.current_page;
 };
 MockMobile.prototype.changePage = function(location) {
   this.current_page = location;
 };

 test("test Auth", function() {
   $.mobile = new MockMobile();
   var _last_alert;
   alert = function(msg) {
      _last_alert = msg;
   };
   $.ajax = function(options) {
      switch (options.url) {
       case '/smartphone/checkguid/':
         options.success({ok:true});
         break;
       case '/smartphone/auth/login/':
         if (options.data.password == 'secret')
           options.success({guid:'10001'});
         else
           options.success({error:"Wrong credentials"});
         break;
       default:
         console.log(options.url);
         throw new Error("Mock not prepared (" + options.url + ")");
      }
   };
   var result = Auth.is_logged_in(false);
   equals(result, false);

   Auth.ajax_login('peterbe@example.com', 'other junk');
   ok(_last_alert);
   ...

(Note: this is copied slightly out of context but hopefully it reveals some of the hacks and tricks I use)

24th of February

JavaScript

Eloquent Javascript by Marijn Haverbeke

Eloquent Javascript by Marijn Haverbeke What a lovely title for a book! I wanted to read a book about the proper way to write Javascript but I couldn't wait any longer for John Resig's Secrets of the JavaScript Ninja which isn't out in print yet (also a great title by the way).

Eloquent Javascript begins very lightly with the basics of Javascript programming. Variables, scope, data structures and control flow. To be perfectly honest I didn't read it very carefully but I believe I did pick up a thing or two at least. The chapter on error handling was useful but the really interesting chapters were "Functional Programming" and "Object-Oriented Programming". What I love about Marijn's style of writing is that he starts very very simple and builds up the code to be better and better. Not based on what you can do but instead why you should do it. As you go along you can then immediately snap up what the benefits are for yourself. Sometimes it's brevity and sometimes it's for faster performance. My only criticism if I'm allowed is that the jargon is quite a lot keep up with. Especially around "constructors" and "prototypes" which is sometimes easy to forget (especially if you're from another language where these things mean different things).

I'm not great at it but I already knew how to write modules and "classes" so ultimately there wasn't a whole lot to take away from it to be honest. Some tricks such as the inheritance function which Marijn introduced was neat and that might be something I'll copy. Nevertheless, this book showed and educated me in why we do things as modules and stuff which I genuinely appreciated.

Thanks for a great book Marijn! Keep up the good work!

5th of February

JavaScript

EditDistanceMatcher - NodeJS script for doing edit distance 1 matching

I needed a very basic spell correction string matcher in my current NodeJS project so I wrote a simple class called EditDistanceMatcher that compares a string against another string and matches if it's 1 edit distance away. With it you can do things like Google search's "Did you mean: poop?" when you search for pop.

Note, this code doesn't check popularity of correct words (e.g. "pop" might appear much more often than "poop" so it'll suggest "pop" if you enter "poup"). Anyway this simple snippet from the unit tests will reveal how it works:

      /* The match() method */
      var edm = new EditDistanceMatcher(["peter"]);
      // edm.match returns an array and remember,
      // in javascript ['peter'] == ['peter'] => false
      test.equal(edm.match("petter").length, 1);
      test.equal(edm.match("petter")[0], 'peter');
      test.equal(edm.match("junk").length, 0);

      /* the is_matched() method */
      var edm = new EditDistanceMatcher(["peter"]);
      test.equal(typeof edm.is_matched('petter'), 'boolean');
      test.equal(typeof edm.is_matched('junk'), 'boolean');
      test.ok(edm.is_matched("petter"));
      test.ok(!edm.is_matched("junk"));

The most basic use case is if you have a quiz and you want to accept some spelling mistakes. "What's the capital of Sweden?; STOKHOLM; Correct!"

For the unlazy this NodeJS code can very easily be used in a browser by simply removing the exports stuff.

edit_distance.js

tests/test_edit_distance.js

Note! I wrote this in an airport lounge so I'm sure it can be improved lots more.

9th of January

JavaScript

RequireJS versus HeadJS

I've spent a lot of time trying to figure out which Javascript script loading framework to use. RequireJS or HeadJS. I still don't have an answer. Neither website refers to each other.

In general

  • To me, it's important to be able to load and execute some Javascript before downloading Javascript modules that aren't needed to render the initial screen. Makes for a more responsive behaviour and gets pixels drawn quicker for Javascript-heavy sites.
  • An understated, massive, benefit to combining multiple .js files into one is sporadic network bottlenecks. Fewer files to download and fewer things can go wrong. These bottlenecks can make a few Kb of a Javascript file take 10 seconds to download.
  • Public CDNs (e.g. jQuery from Google's CDN) is an extremely powerful optimization technique. Not only are they extremely fast, it's very likely they're preloaded because some other site uses the exact same URL.
  • Where does it say that Javascript has to be loaded in the head? Even html5-boilerplate loads Javascript just before the </body> tag.
  • Realistically, in the real world, it's not uncommon that you can't combine all .js files into one. This is not true for web apps that consists of just one HTML file. One page might require A.js, B.js and C.js but another page requires A.js, B.js and D.js. Requires manual thinking whether you should combine A,B,C,D.js or A,B.js + C|D.js. No framework can predict this.
  • All loading and browser incompatibility hacks will eventually become obsolete as browsers catch up. Again, requires manual thinking because supporting and ultra-boosting performance might have a different cost today compared to a year from now. The most guilty of this appears to be ControlJS
  • I'm confident that optimization in terms of file concatenation and white space optimization does not belong to the framework.
  • Apparently iPhone 3.x series can't cache individual files larger than 15Kb (25Kb for iPhone 4.x). That's a very small about if you combine several large modules.
  • Accepting the fact of life that sporadic network bottlenecks can kill your page, think hard about asynchronous loading and preserved order. Perhaps ideal is a mix of both. What framework allows that? (both RequireJS and HeadJS it seems)
  • Loading frameworks are not for everything and everyone. If you're building something "simple" or landing page like Google's search page frameworks might just get in your way.

RequireJS

  • Author well known but his Dojoesque style shines through in RequireJS's syntax and patterns.
  • Is only about Javascript. No CSS hacks or other html5ish boilerplates.
  • Gets into the realm of module definitions. Neat but do you want the loading framework to get involved in how you prefer to write your code or do you just want it to load your files?
  • All the module definition stuff feels excessive for every single project I can imagine but we're entering an era of "web apps" (as opposed to "web sites") so this might need to change.
  • What you learn in using RequireJS you can reuse when building NodeJS (a server-side framework). It's also possible to use RequireJS in Rhino (server-side Javascript engine) but personally I haven't reached that level yet.

HeadJS

  • Author relatively unknown. quite well known too. Author also of Flowplayer and jQuery Tools.
  • Contains a kitchen sink (CSS tricks, modernizer.js) but perhaps they're really quite useful. After all, you don't write your web site in Assembly.
  • There's a fork of HeadJS that does just the Javascript stuff. But will it be maintained? And does that defeat the whole point of using HeadJS?
  • With its CSS hacks (aka. kitchen sink) HeadJS seems great if you really care about combining HTML5 techniques with Internet Explorer.
  • This awesome experiment shows that HeadJS really works and that asynchronous loading can be really powerful. But ask yourself, are you ready to build in an asynchronous way?
  • With HeadJS I can label a combined and optimized bundle and load my code once that bundle is loaded. Can I do that with RequireJS? It seems to depend on the filename (minus the .js suffix).
  • Makes the assumption that just because a file is loaded the order of execution is a non-issue. This means you might have trouble controlling dependencies during execution. This is a grey area that might or might not matter depending on the complexity of your app.
  • A feeling I get is that HeadJS without the CSS kitchen sink stuff reduces to become LabJS or EnhanceJS.

Other alternatives

The ones I can think of are: ControlJS (feels too "hacky" for my taste), CommonJS (not sufficiently "in-browser specific" for my taste) and EnhanceJS (like HeadJS and LabJS but with less power/features)

The one I haven't studied as much is LabJS. It seems more similar to HeadJS in style. Perhaps it deserves more attention but the reason HeadJS got my attention is because it's got a better looking website.

In conclusion

You mileage will vary. The deeper I look into this I feel personal taste comes into play. It's hard enough for a single framework other to write realistic benchmarks; even harder for "evalutators" like myself to benchmark them all. It gets incrementally harder when you take into account the effects of http latency, sporadic network bottlenecks, browser garbage collection and user experience.

Personally I think HeadJS is a smoother transition for general web sites. RequireJS might be more appropriate when write web apps with virtually no HTML and a single URL.

With the risk of starting a war... If you're a Rails/Django/Plone head, consider HeadJS. If you're a mobile web app/NodeJS head consider RequireJS.

UPDATE

Sorry, I now realise that Tero Piirainen actually has built a fair amount of powerful Javascript libraries.

7th of November

JavaScript

Javascript tip: nifty use of the console.log function in Firebug

A classic blunder in Javascript client side apps is heavy use of the incredibly useful Firebug feature that is console.log() and then forgetting to remove any such debugging and thus causing Javascript errors for people without Firebug. To remedy this use this little nifty function:

 function log() {
   if (window.console && window.console.log)
   for (var i = 0, l = arguments.length; i < l; i++)
     console.log(arguments[i]);
 }

That way you can do plenty of debugging and if you accidentally leave a logging line in your code it won't break anything even if they don't have Firebug installed/enabled. Also you can easily "annotate" your debugging by writing two things in one line. Like this:

 function foo(bar) {
    log("bar is:", bar);
    return bar * 2;
 }

20th of October

JavaScript

Why I gave up on JQuery UI's autocomplete

I was happily using Jörn Zaefferer's jQuery autocomplete plugin but then I found out that it had been deprecated and I should instead use the jQuery UI's autocomplete plugin instead.

After "upgrading" I started getting suspicious. Is it actually worse than the old one?


> Read the whole text (229 more words)

18th of October

JavaScript

Nasty JavaScript wart (or rather, don't take shortcuts)

I had a piece of code that looked like this:

 function add_to_form(f, all_day) {
   console.log(all_day);
   if (all_day)
     $('input[name="all_day"]', f).val('1');
   else;
     $('input[name="all_day"]', f).val('');
   console.log($('input[name="all_day"]', f).val(''));
   return f; 
 }

When I ran it, the console output was this:

 true
 (an empty string)

What had happened was that I had accidentally put a semi-colon after the else statement. Accidentally as in stumbled on the keyboard. I didn't spot it because semi-colons are so common in JavaScript that you sort of go blind to them.

The wart was that it didn't cause a syntax error. IMHO it should have because you'd expect there to always be something happening after the else.

So instead of using the shortcut notation for if statements I've decided to write it out in full instead:

 function add_to_form(f, all_day) {
   if (all_day) {
      $('input[name="all_day"]', f).val('1');
   } else {
      $('input[name="all_day"]', f).val('');
   }
   return f; 
 }

Optimizers like Google Closure will do a much better job optimizing the code than I ever will anyway.

14th of September

JavaScript

In jQuery, using the :visible selector can be dangerous

In jQuery, using the :visible selector can be dangerous And by "dangerous" I mean super slow to the point of making your browser shake of over exhaustion.

I have a big fat table where on the left hand side of each row there's a little toggle to open up an initially hidden sub-table. And there are toggles for those sub-tables to open up further sub-tables. It might sound complicated but it works great. The code for each toggle looks something like this:

 $('a.toggle-order-on').click(function() {
    var tbody_parent = $(this).parents('tbody');

    $('tr.printdisplay:hidden', tbody_parent).show();
    $('tr.outdoor-marketing:hidden', tbody_parent).show();
    $('tr.digital:hidden', tbody_parent).show();

    // expand the little table too
    $('a.toggle-printdisplay-on', tbody_parent).click();

    var td_parent = $(this).parents('td');
    $(this).hide();
    $('a.toggle-order-off:hidden', td_parent).show();

    return false;
 });

Note the heavy use of the super useful :hidden selector which is basically a reversing wrapper on the :visisble selector

What I then needed was a way to open up every single row in the whole table with one click. Here was the code I wrote:

 $('a.toggle-order-on:visible').trigger('click');

See? Makes sense does it?

Problem with this was that when the table was big sometimes clicking this would make my otherwise fast browser (Chrome or Firefox) stutter and sometimes stall or at worst the alert pop-up about "a script is slowing this page down" would appear.

So I started the Firebug Profiler and clicked a couple of times and collected some numbers. On average it took 3-4.5 seconds!! and about 20,000-35,000 calls to complete the full expansion. Yikes! About 90% of the time spent by jQuery was on the visisble() function.

Solution: Instead of using the click trigger I simply just called the .show() effect on all things manually without using any :visible or :hidden operators. Here's the new code:

 $('tr.printdisplay').show();
 $('tr.outdoor-marketing').show();
 $('tr.digital').show();
 $('tr.printdisplaydetail').show();

 $('a.toggle-order-off').show();
 $('a.toggle-order-on').hide();

 $('a.toggle-printdisplay-off').show();
 $('a.toggle-printdisplay-on').hide();

This time, with the profile again, I it took on average 0.2-0.3 seconds and required about 2000-4000 calls. HUGE difference.

So, remember that next time. Don't just re-use working code en mass if it's using a much of :visible or :hidden selectors somewhere in there.

1st of September

JavaScript

Local NodeJS development environment with Nginx

I'm brand spanking new to the node.js web application development. The framework I'm currently using is express which seems OK. So I've got an app that consists of 1 static HTML file, a lot of Javscript/CSS/image resources and some express GET and POST views that return small snippets of HTML. All data will be loaded with AJAX to avoid having to use any HTML templating on first load. What's cool about this is that it's soo fast! Everything except the JSON data can be loaded from an Nginx server.

At the moment I've got a light static HTML page that loads about 240Kb of Javascript and CSS (jQuery UI is big) and a couple of bytes of JSON data pulled from Node. As a little anal perfectionism I put an Nginx server in front so that Node doesn't have to serve any of the static files. To get that you have to have a Nginx site enabled that looks like this:

 server {
    root /home/peterbe/task-calendar/static;
    location / {
      if (-f $request_filename) {
          add_header X-Static hit;
          access_log   off;
      }
      if (!-f $request_filename) {
          proxy_pass http://127.0.0.1:8000; # where Node is running
          add_header X-Static miss;
      }
    }
 }

I think much of the fun of working with this app is that it's a delight to see it load in the browser without any sluggishness or delay. Lovely!

 

Older entries Order entries