My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Friday, March 16, 2012

On Obtrusive Polyfills

I'll try to make the point short and simple, starting with the tl;dr version: if you create a polyfill and during features detection you realize this cannot work, drop it and let other libs deal with it.

Broken Object.defineProperty

This is just one case really annoying. Bear in mind I am not talking about "making perfect polyfills", this is almost impossible most of the case, I am talking about broken runtime even if you did not really do anything that special.
It was the case of Object.defineProperty shimmed through es5-shim code ... this library is good but that method, as many others, are simply broken.
I was trying to add a setter/getter in IE < 9 and shit happened, more specifically a thrown exception happened ... the repository itself explains that this method and others should fail silently ... so it's OK for the developer to know about it and avoid trusting these methods ...


This Is Not OK

If I check if Object.defineProperty is there and this is all I need to know, I don't want to double check which version of IE, if IE, it is, neither I want to check anything extra.
I simply trust the fact the browser, or some library, fixed the problem for me and I can use this method as it is.

if ("defineProperty" in Object) {
// I want to use it, wouldn't check for it otherwise
}

A broken shim doesn't make anyone life easy while that simple condition in my code could redirect my logic in a completely different approach.
Since in IE < 9 that method simply does not make sense to exist, then it should not exist, period.

Remove The Broken Shim

I hope, and expect, that es5-guys will simply delete Object.defineProperty afterward, once realized it's not usable.
I would not compromise entirely theObject.create but again, if defineProperty() is not there there is no bloody point on using create() too.
Let other libraries deal with the fact this is missing in their own way since every single case could be different: someone simply need to inherit another object, someone else might need the method as it should be.

As Summary

A shim/polyfill that works 90% is OK, specially if the API is covered 100% and even if behind the scene things are not identical, but a polyfill that let a piece of code think everything is fine and the whole app breaks who knows when and why should not be exposed at all or, if you really want to bring similar functionality, it should be exposed prefixed, i.e. Object.$defineProperty() so that the rest of the code is aware that such method exists but it's limited.

Thanks for understanding

Friday, March 09, 2012

A Tweet Sized Queue System

The Code

This is the 138 bytes version:

function Queue(args, f) {
setTimeout(args.next = function next() {
return (f = args.shift()) ? !!f(args) || !0 : !1;
}, 0);
return args;
}

While this is the 96 one:

function Queue(a,b){setTimeout(a.next=function(){return(b=a.shift())?!!b(a)||!0:!1},0);return a}


The Why

In almost every QCon London talk I have heard the word asynchronous. Well, the aim of the tweet sized function I have just written above is to make things easier.
After I have implemented builder/JSBuilder.js for wru, so that Python is not needed anymore to build the tiny library, I needed to make builder/build.js usable in a way that asynchronous calls through node won't bother, at least visually, the normal flow of the script.
After that I have thought: "why not making a generic Queue function with Promises like approach" ?

The What

It's quite straight forward, you create a queue, you use the queue. You might eventually pollute the queue or change its order, since the queue is nothing different from a generic Array with an extra method on it: next().
Here a basic example:

Queue([
function (queue) {
// do amazing stuff asynchronously
setTimeout(function () {
queue.message = "Hello Queue";
queue.next();
}, 500);
},
function (queue) {
// do something else
alert(queue.message);
// Hello Queue
queue.next(); // not necessary at the end
// does not hurt thought
}
]);


That's Pretty Much It

So, the queue argument is the array created initially to define the ordered list of function.
This means you can recycle this variable even adding custom properties but most important is that you can change the queue via Array.prototype.splice/unshift/pop/push() methods and decide the future or the next function to execute runtime, if needed.
The only extra bit is about returning true or false in case there was a next() to execute or not.

Last, but not least, of course you can create new Queue([]) inside queues ... so, this is actually more powerful than many other queue systems I have seen so far and ... hey, 96 bytes: enjoy!

Thursday, March 08, 2012

I Heard You Like To Write Less

Update apparently this proposal is being considered in es-discuss ... not the implicit return so far but the "redundant" function keyword.
This is last draft from Brendan Eich:

FunctionDeclaration:
function Identifier ( FormalParameterList_opt ) { FunctionBody }
Identifier ( FormalParameterList_opt ) [no LineTerminator here] { FunctionBody }

ShortFunctionExpression:
Identifier_opt ( FormalParameterList_opt ) [no LineTerminator here] { FunctionBody }
Identifier_opt ( FormalParameterList_opt ) => InitialValue



I'm @qconlondon waiting for the next talk so I decided to take a couple of minutes to blog about this little experiment.
In ES-Discuss developers are still talking about function keyword, if it's needed or not.

I believe the fact CoffeeScript has no explicit function is one of the major reasons devs have been attracted so I made it even simpler.

Just Drop The Function

With current ES 3, 5, or 5.1 syntax I can't really see problems or ambiguity removing that keyword but if you find a case that could fail please let me know.
Of course if we use a keyword we should be able to understand the difference, i.e. with for, if, or others, and this simple test page is just an experiment: you write some code, you "functionize" it, and if the code does not run it's showed highlighted in red.
The RegExp is quite simple and straight forward and parsing time should never be a problem even for big projects.
The return is implicit, a bit Ruby style, but of course you can chose to return in the middle of a function.
Thing is, the very last statement will be returned and you can play with results.

I wonder if anyone would use such syntax on daily JavaScript coding. The parser needs improvements in any case so just think about it and let me know. Cheers

Friday, March 02, 2012

What's localStorage About

I've read even too many articles recently talking about storing anything you want in the localStorage ... and I believe this is wrong in so many levels.
First of all, localStorage is not a database, 'cause if you consider it a database you should have considered a database document.cookie before ...

As Simple As That

document.cookie has been there, problematic as it is, since ever.The limit of this technique has always been the 2Mb on average across different browsers.
Have you ever asked yourself what the hell is document.cookie doing and how comes it's instantly available?
Well, it's about storing some stuff in your hard disk or your browser (SQLite) database, so that every single request will send this file loads of key/values pairs through the HTTP request.
The side effect of this technique is that more you pollute cookies in your site to remember stuff, the more the interaction will be slower, specially on mobile, since all these info have to be sent to the server for each bloody request.

What's localStorage Good For

First of all don't forget localStorage does synchronous I/O which means it's blocking and the bigger it is, the slower it will be to retrieve or store data. Secondly, don't forget that if every script in your page is using it, the possibility that its rich 5Mb gonna be filled up are higher.
As summary, the moment you start storing files there you are kinda doing it wrong. You don't know how long it takes to retrieve or store data in the localStorage and the moment you feature detect this delay you have already potentially compromised your page/app visualization time.
localStorage best practice is to keep it small, as small you have kept, hopefully, until now, any document.cookie related task.
Of course if your code is the only one using localStorage, and you have things under control, you may think to use it as generic key/value paris DB but on Web, where usually more than a framework/library is in place, you can't pollute this storage as much as you like because is like polluting the global scope with any sort of crap ... and I hope we got this is bad, right?

As Less As You Can Remembering It's Public

True story bro, if you care about your code behavior don't trust, believe, use, this storage that much. Store what you think is necessary and nothing more, use proper DBs interfaces to store more, use the browser cache if you have your server under control, use the manifest if you want to make your app available off-line.
If you are thinking to speed up, without considering localStorage side-effects, the initialization of your page, storing your script once because it's too heavy ... well, the moment you both block the I/O to read that script and the moment you gonna evaluate it, you have gained zero performances boost in 90% of the cases.
Keep it small, think about other libraries, never be greedy with the localStorage, the worst case scenario is that your web page will temporarily kill your same startup time, or the stored data is more than 5Mb and we are screwed, or other libs in your page may be so greedy to erase everything that's not in their prefixed key namespace in a call

for (var key, i = localStorage.length; i--;) {
key = localStorage.key(i);
if (key.slice(0, 3) !== "my-") {
localStorage.remove(key);
}
}

Without considering the fact that a single clear() call performed from another library would destroy all the data you rely on.

Bear In Mind

document.cookie should be used as client/server channel while localStorage is client only matter. Put in cookies what the server should know, and put in localStorage what you would like to remember for the user always keeping in mind, as explained before, that its data is available for any other lib in your page.

So ... now you know ;)