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

Saturday, January 23, 2010

Better JavaScript Classes

Update This post continues here, in the JavaScript _super Bullshit one.


In my precedent post I have discussed about few common JavaScript errors, included the classic new Class() call to retrieve a runtime created function, populating its prototype.
While my suggestion is both semantic and reasonable, I am pretty sure nobody on earth will ever implement that native Function wrapper, and this is the reason I am posting again, this time hopefully with a better suggestion.

JavaScript Class Abstract Concept

It's extremely hard to understand for those with classic OOP background but JavaScript has no Classes, just objects, where functions are first class objects but still objects!
Assumed this, we can try in any case to think about a JavaScript Class as a "function which aim is to create instances of function itself".

What Is Wrong Right Now

What I argued about in my precedent post is that this statement is too often unconsidered:

// try with Mootools or some other library
new Class({}) instanceof Class;
// FALSE, since Class returns a function
// and not the created instanceof Class

Above misconception about what a Class is and how meaningless and redundant is the new keyword in latter case is truly annoying me!
The reason developers want "Classes" in JavaScript is because they think their OOP knowledge is better than what JS already offers, so why on earth they should create and use such hybrid nonsense?

A Class IS A Function

Nothing more and nothing less. The fact we would like to use that function to create and initialize instances is just how every Functions work, or if we prefer, a developer convention and a quick way to chain a prototype into an object.
Since a Class is a Function, and whatever "new Class()" will always be an "instanceof Function", Class.prototype should be exactly the Function.prototype one, so that nobody can ever say again: "Look, I have created a Class" ... no bullshit Sherlock, you created a Function!

How To Define A "Class"

If we think about classical OOP languages, the only way to use a Class is to define it indeed. In few words, if the plan is to use a new Class() approach, how about a mandatory Class definition Object ?

// the most basic Class implementation
function Class(
// Class definition object: mandatory
__proto__
) {
// define the "Class"
// if the definition object has a constructor property
var Class = __proto__.hasOwnProperty("constructor") ?
// use it ...
__proto__.constructor :
// otherwise create one and assign it
(__proto__.constructor = function () {})
;
Class.prototype = __proto__;
return Class;
}

// we already said that a Class is simply a function ...
Class.prototype = Function.prototype;

Above code is basically all we need to start using new Class(definition) approach:

// class creation via definition object
var Person = new Class({

// this is our Person constructor
constructor: function (name) {
if (name) {
this.setName(name);
}
},

// this is a public property
name: "anonymous",

// this is a public method
setName: function (name) {
this.name = name;
}

});

Person instanceof Class; // true
Person instanceof Function; // ... as well

var dunno = new Person;
dunno instanceof Person; // true
dunno.name; // anonymous
dunno.constructor === Person; // true

I think this approach is as elegant as simple, but there is still a lot to consider about it.

A constructor IS An Implicit Init Method

I don't really know "when" it started and I am not sure about "why", but lots of libraries use this extra call to init/initialize/initializator/WTinitF method. If we think about this approach, it's like this:

// the JavaScript way
var a = [];

// the init way
var a = [];
a.init();

Now, think that for every created instance, rather than simply use the constructor for what it is, a method able to initialize an instance as is for basically every OOP language, we need to access to the instance chained prototype to execute a second init ... not sure what you think about it, but this sounds a bit redundant to me ...
A Class constructor is already able to initialize an instance, that is simply why I have decided to be semantic and use just the constructor method as is rather than an extra init call.

A constructor Must Be Unique

The definition approach is something good in any case, but above implementation does not consider one of the best features in JavaScript: the context injection.
If we would like to reuse common methods, as example for a mixin or a hybrid prototype, initial suggestion is not enough.
The moment we use the same constructor to initialize a variable, we are already stuck. Even worst, we cannot reuse the same definition object to partially define one or more classes with common methods or initialization.
How to solve this? We need to chain the definition object in order to be able to extend the created Class.prototype for everything we need.

// chained Class definition example
var Class = (function () {

// the public Class function
function Class(__proto__) {
// the created "Class"
function Class() {
// initialize the instance via original constructor
__proto__.constructor.apply(this, arguments);
}
// assign the prototype ...
Chain.prototype = __proto__ || (__proto__ = {});
// ... and create the chain, assigning the right constructor
Class.prototype = new Chain(Class);
return Class;
}

// runtime __proto__ chain with right constructor assignment
function Chain(Class) {
this.constructor = Class;
}

Class.prototype = Function.prototype;

return Class;

})();

We are still far away from a proper solution, at least we can now reuse a generic function to initialize one or more instances and we can reuse definition objects

var commonDef = {
constructor: function (name) {
if (name) {
this.name = name;
}
},
name: "unknown"
};

var Named = new Class(commonDef);
// this operation won't change commonDef object
Named.setName = function (name) {
this.name = name;
};


var Person = new Class(Named.prototype);
// this operation wont change Named.prototype
Person.prototype.getName = function () {
return this.name;
};

Thanks to prototype chain we are now able to extend directly another prototype, so that new Person, as example, will be instanceof Named too.

Don't Mix Class Definitions And Prototypes

While it could look good, the latter example has truly a bad design.
A Class definition should be a concept a part. If we use another Class.prototype to define a new Class we are mixing definitions with "defined" concept.
To extend or inherit from another object there must be a specific method.
To better explain myself, let's consider this simple PHP example:


class A {
// here we define the class
public function doStuff() {
}
}

class B extends A {
// we are extending another class
// but we are still defining here class B structure
public function __construct() {
}
}

If we pass directly a Class.prototype as definition, we are basically doing this, rather than what I have already showed:

class B extends A {}

Can we see the difference? B extends A and nothing else, there is no definition for B, everything is just like A.
OK, in JavaScript we can add and remove properties and methods from a prototype or a single instance in whatever moment, but aren't we trying to emulate somehow classic OOP paradigm? So let's agree that if we like this approach, prototypes must be untouchable after Class definition, and defined prototypes mustn't be used as Class definition ... do we agree?

Function.prototype.extend FAIL

I am the first one in error, I have tried to defined dunno how many times a proper Function.prototype.extend in order to make every function extensible.
The problem, specially in this case/approach, is that functions are functions, while Classes are Classes. If we make a generic "extend" method available for any kind of function, even those never used to create instances, we are simply polluting without a valid reason a shared prototype: shared between classes and functions.
Moreover, the fact a Class is extending another one should be instantly recognizable, and not something that could happen in the middle of a generic session, do you agree?
In few words, some common approach is not truly readable/reasonable:

function B() {
// something happens here
};
// lazy extend, could happen everywhere
// even with functions such Math.max, kinda nonsense
B.extend(A);
B.prototype = {...};

// new Class pattern
var C = new Class({
// long definition object
})
// we need to scroll till the end to understand
// if C.prototype is chaining another one
.extend(B)
;

If we compare again with precedent PHP snippet, or every other OOP language where extends is basically the first thing we can understand about a class, I think nobody should ever use above pattern in JavaScript: it's cool, it's dynamic ... but it's absolutely wrong as well if we are trying to bring classic OOP approach into this language!

Only Explicit Extend Via Definition Object

At least for this topic, most common libraries are already implementing what I am talking about, which is something like this:

var Man = new Class({

// first thing ever into definition object
extend:Human,

// optional constructor ir simply
// the rest of the definition
gender:"male"

});

The fact extend must be explicit is simple: nobody should be able to pollute Object.prototype adding an extend method/property, if we recycle objects we don't want to extend automatically any inherited extend from internal chains.

Public Statics

Almost the last piece of the puzzle, the ability to add via definition public static properties or methods.
This could be another special property name, used like this:

var File = new Class({
statics:{
exists:function (fileName) {
// some cool code here
return found;
}
},
constructor: function (fileName) {
this.name = fileName;
},
exists: function () {
return File.exists(this.name);
}
});

var fileName = "index.html";
var index = new File(fileName);

// it should be always true
File.exists(fileName) === index.exists();


Class.definition

I am trying to keep writing semantic code so I guess the last piece ever to add into the run-time created class is simply one: the definition object.
For both introspection and tricky code, I think it's a good idea to be able to retrieve the definition object. It could be reused, it could be analyzed, there are several things that could let us think: how to get back that object?
Well, since the extremely useful __proto__ property is not standard, the only way to retrieve that object is to associate directly to the Class, being its definition, and via definition property name. Is there anything more semantic and logic than this?

var def = {what:"ever"};
var MyClass = new Class(def);

MyClass.definition === def; // true

Now we can say we have everything!

this._super bullshit

Don't get me wrong, I do appreciate the effort every framework is putting in order to have a nice way to retrieve a super method, if any, but what we need to understand is that:
  1. _super, parent, whatever it is, requires to be portable for each parent "level", not just one
  2. to make first point possible, _super requires a lot of initial parsing, wrapping, and runtime substitutions, an inevitable performances bottleneck, as showed in my old tests
  3. wrappers are anonymous and all equals, almost impossible to debug
  4. wrappers could fail, causing disasters if the "super" does not fallback into the original one for that level
  5. try catch for super are performances killers, at the same time the best way to avoid disasters
  6. wrappers could cause infinite loops, if super is not handled properly
  7. super/parent is not an instance related property!!!
The latter point is the one that should suggest us to think about "super" misconception.
In classical OOP the super/parent keyword is related to the current method, it is never an instance property.
When we need "super" we are talking about the super definition of the overridden method, if any, or another one up to the initial ring of the prototypal chain.
In few words, super has nothing to do with the instance, but for JavaScript nature, the simplest way to change runtime its reference, is to attach it to the instance.
Last, but not least, I have personally encountered problems, dunno how many times, with a whole stack or super wrappers without being able to understand which method was failing and where!
I am pretty sure that developers perfectly know what I am talking about, so while this._super can be "cool", have we never thought how much better explicit injections could be?

var A = new Class({
doStuff: function () {
this.where = "A";
}
});

var B = new Class({
extend:A,
doStuff: function () {
// zero ambiguity, zero wrappers
// best performances + fast debug
A.prototype.doStuff.call(this);
// if some error occurs here
// we know where it did, rather than a wrapper
this.where += "B";
}
});

Furthermore, while in classic OOP super/parent is usable for properties as well, I have never seen a proper implemntation for this in any framework.
As summary, while "super" or "parent" is something truly natural for classic OOP developers, there is no easy way to implement it properly in JavaScript, specially because if the same function can be used as method for 3 different classes, as example, the keyword super there will completely lose its meaning, basically the reason the only way to implement it, is to attach, substitute, and execute, runtime, via instances, rather than proper methods definition lookups. This is why my Class implementation does not provide such problematic "solution" for lazy developers.

WebReflection Class


var Class = (function () {

/*!
* JavaScript meaningfull Classic OOP Class Factory
* @author Andrea Giammarchi
* @license Mit Style
*/

/**
* Public exposed Class function
* @param Object the Class definition
*/
function Class(definition) {

// create the function via named declaration
function Class() {}

// find out if this is an extend
var $extend = hasOwnProperty.call(definition, "extend");

// temporary shortcut for inherited statics
var $;

// reassign the Class if there is a constructor ...
if (hasOwnProperty.call(definition, "constructor")) {
// wrapping it for faster execution
Class = constructor(definition.constructor);
}

// assign inherited public static properties/methods, if defined in the extend definition
if (
$extend &&
hasOwnProperty.call($ = definition.extend, "definition") &&
hasOwnProperty.call($ = $.definition, "statics")
) {
extend.call(Class, $.statics);
}

// assign public static properties/methods, if defined
// eventually overwrite inherited statics
if (hasOwnProperty.call(definition, "statics")) {
extend.call(Class, definition.statics);
}

// assign the prototype accordingly with extend
($extend ?
// chain the prototype extending it with the definition object
extend.call(Class.prototype = create(definition.extend.prototype), definition) :

Class.prototype = create(definition)
)
// be sure the constructor is the right one
.constructor = Class
;

// static public definition
Class.definition = definition;

// return the created class
return Class;
}

// wrap the constructor via closure
function constructor(constructor) {
// creating a named declared Class function
function Class() {
// return in any case for dual behaviors (factories)
return constructor.apply(this, arguments);
}
return Class;
}

// extend a gneric context via __proto__ object
function extend(__proto__) {
for (var key in __proto__) {
if (hasOwnProperty.call(__proto__, key)) {
this[key] = __proto__[key];
}
}
return this;
}

// trap the original Object.prototype.hasOwnProperty function
// as shortcut and hoping nobody changed it before this file inclusion ...
var hasOwnProperty = Object.prototype.hasOwnProperty;

// quick/fast Object.create emulator, if not in ES5
var create = Object.create || (function () {
function Object() {}
return function (__proto__) {
Object.prototype = __proto__;
return new Object;
};
})();

//* optional standard "for in" for Internet Explorer
// it could be removed if we don't define "magic mathods" in definition objects
// Internet Explorer does not enumerate properties/methods
// with name present in the Object.prototype
if (!({toString:null}).propertyIsEnumerable("toString")) {
// if this happens, to make the extend consistent
// we need to force Object.prototype names
extend = (function ($extend) {
function extend(__proto__) {
for (var i = length, key; i--;) {
if (hasOwnProperty.call(__proto__, key = split[i])) {
this[key] = __proto__[key];
}
}
// execute the original extend in any case for other properties/methods
return $extend.call(this, __proto__);
}
// constructor is not in the list since there is a re-assignment in any case
var split = "hasOwnProperty.isPrototypeOf.propertyIsEnumerable.toLocaleString.toString.valueOf".split(".");
var length = split.length;
return extend;
})(extend);
}
//*/

// a Class is a Function and nothing else
Class.prototype = Function.prototype;

return Class;

})();

A simple test case:

var A = // base class
new Class({
constructor: function () {
alert("A");
},
toString: 123
})
;

var B = // extended class
new Class({
extend:A,
constructor: function () {
A.call(this);
alert("B");
},
toString: 4
})
;

var b = new B;
// 4, true, true, true in every browser
alert([b.toString, b instanceof A, b instanceof B, b.constructor === B]);


Personal Thoughts

What I don't like is that extend, as statics, become part of the prototype as well. Unfortunately I decided that these words should be kinda reserved in order to speed up Classes creation.
At the same time, Classes creation is something performed once and never again, so I may decide to change in the future the way I define the prototype, simply looping via "for in" and attaching properties. This could cause some sort of problem with truly inherited stuff, so right now I guess this is it.

As Summary

My Class implementation does not probably bring anything new in the panorama but what it does, it does it properly. The definition object has precedence over inherited properties/methods. Super or extra methods calls should be explicit, avoiding redundant wrappers, improving performances, and making debug easier. Constructors, if present, are used as instance initializers, as it has always been in classic OOP. Every definition could be wrapped in a closure and returned, in order to have shared private properties or methods and Classes are finally instanceof Class, or better, are simply functions.

Monday, January 18, 2010

Good Old And Common JavaScript Errors

... I won't write any introduction, but I'll let you comment, OK?

for loops (plus ++i)



for(i = 0; i < 10; i++){}
// global i defined

for(var i = 0; i < something.length; i++){}
// cache the length if it won't change during the loop
// associate once only under certain conditions to speed up

for(var i = 0; i < 10; ++i) {}
// there is absolutely nothing wrong in above loop

Few people told me something like: "doode, if you use ++i at the end you need to write i < 11 'cause i will be 1 inside the loop" ... basically the for loop has been rarely understood, let me try again:

// directly from C language, 1972
for(

// optional inline declaration, coma accepted for more vars
;

// optional condition to verify
// if undefined, it loops until a break is encountered
// this condition is performed BEFORE the first loop
// if false, the loop will never be executed
;

// optional POST operation, it will never be executed
// if the condition is false, "", 0, or null
// it is executed in any case AFTER the loop, if any
){};


// example
for(var i = 0; i < 1; ++i){
// one single execution
// i will be 0 here
};
// i will be 1 here

The reason ++i is preferred over i++, whatever Google go language decided about it, is that i++ and ++i are totally different and you need to understand when, or why, you need i++ or ++i.
While ++i increments directly the variable, returning the variable itself, if numeric, i++ returns a NEW variable with the precedent value AND it increments the i var as well.
Pure JavaScript Example

function Num(value) {
this.value = value;
};
Num.prototype.valueOf = function () {
return new Num(this.value);
};
Num.prototype.toString = function () {
return "" + this.value;
};

var a = new Num(0);
var b = a++;
alert(a); // 1
alert(b); // 0
alert(a == b); // false

// again

var a = new Num(0);
var b = ++a;
alert(a); // 1
alert(b); // 1
alert(a == b); // true

It does not matter if speed speaking, the difference is "not that consistent", it matters that we are programmer, and if two things mean different things, we want to understand them, am I wrong?

Already defined variables, and scopes


Another piece of code you can find around the net, is this:

// something defined globally
var num = 1;

(function () {
// try to set a default
var num = num || 0;
})();

Above code will never work, and it's the ABC about scope and functions.
It's exactly like this:

// something defined globally
var num = 1;

(function (num) {
// now try to find the global num without this. or window. ...
})();

Same is for arguments:

function A() {
// this is actually correct since arguments shares same scope
// no shadowing in this case, thanks to qfox
var arguments = arguments || [];
};

What we need to understand, is that next code is ALWAYS true:

var u = 123;
(function () {
var u = (typeof u === "undefined");
// u is TRUE!!!
})();

The moment we define a scoped variable, it has precedence over whatever outer scope: bear in mind!!!

new Array, new Object


I can't wait the day people will stop to prefer this code:

var a = new Array(); // NOTE: no length/elements specified
var o = new Object(); // NOTE: no object to wrap/convert

rather than:

var a = [];
var o = {};

There are no excuses at all. First of all, the "new Array/Object" way is unsafe, since both constructors can be easily redefined/wrapped, as explained ages ago in many different security related JavaScript issues.
Moreover, we have both more bytes to digest and reduced performance, and a compiler/minifier that is so cool that will change automatically new Array into [] will simply potentially break our code so we cannot even rely improvements with production code.
So ... PLEASE DON'T!

... and new Function ...

Hey, Java guys, please answer this question:
Would you ever use in your Java life a factory method via "new" ???
Seriously, I don't get it ... let's go one step back ...

The Meaning of Factory


The essence of the Factory Pattern is to "Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses."


JavaScript Functions Behavior

If a JavaScript function returns a primitive value such: "string", true, false, null, int, double, new function will return an instanceof that function, overriding the returned result.
Same is for no returns, or return undefined.
If a JavaScript function returns an object, the usage of new is completely redundant and useless.

Array, Function, Object, and RegExp are Factory!!!



var a = Array();
var b = new Array();
var c = [];
[
a instanceof Array,
b instanceof Array,
c instanceof Array
]; // true,true,true


Boolean, Date, Number, and String are both primitive casts and Object constructors!!!



var a = 1;
var b = Number("1");
var o = new Number(1);
a === b; // true
a === o; // false
a == o; // true
a instanceof Number; // false
o instanceof Number; // true
typeof a; // number
typeof o; // object

As summary, and again, please repeat with me:
If a JavaScript function returns a primitive value such: "string", true, false, null, int, double, new function will return an instanceof that function, overriding the returned result.
If a JavaScript function returns an object, the usage of new is completely redundant and useless.


new Class(whatever) === new Factory(whatever)!!!


This is the most misunderstood part that seems so logical but does not make sense at all. 99.9% of cases and in different libraries we can find the classic call to new Class to create what people think is a Class in JavaScript (in few words, to populate the prototype of a runtime created function).
Wait a second ... did I just say: to create a Class?
Uhm ... so, we don't create an instance ... we create a class ... uhm again, so, we are using a Factory, isn't it? :zizi:

Function.createClass() would be hundreds of times more correct, logically speaking, but we all like the new Class, right?
Well, I wonder how many Java Gurus create they Java classes via new Class() on daily basis ... what? You have to define a class, not to create one? ... oh, REALLY???
MooTools use new Class to create runtime functions, parse the configuration object in order to populate the created function prototype, extending it with a completely useless this, that could be simply Class.prototype without useless runtime instanc`es creation for each Class, to finally return a function that is not instanceof Class ... not even primitives values in JavaScript are that ambiguous, isn't it?

new Class({}) instanceof Class; // FALSE!!!

MooTools is simply one in the ocean of libraries that use this misconception to create Functions, not Class, Function.
Considering that JavaScript has no classes, something apparently unacceptable for GWT and friends maniacs that absolutely need to compile their Java application inevitably into a prototypal based programming language as JavaScript is, thinking they have more power over the application, I agree that classic OOP is something so intrinsic in the IT panorama, that it will never die and it could make somehow things simpler for newcomers into JavaScript. OK, I am with you ... can we at least agree about the fact new factoryMethod does not make sense at all?

Logically Speaking ...


Rather than nonsense why don't we simply respect JavaScript native behavior?
If we consider native constructors behaviors such Boolean, Number, or String, I have already described what's up if we use new or not.
There is a massive difference between new and not new ... so why don't use the same behavior for Funciton?

// example
var f = Function("return 'function'");
alert([f instanceof Function, f()]);
// true,function

var f = new Function({toString:function(){return "instance"}});
alert([f instanceof Function, new f()]);
// true,instance

In few words we can easily think about Function as a primitive function creator AND as a function instances creator, those that we'll love to use to instantiate our application objects. Does it sound really that silly?

var Function = (function (Function) {
// (C) WebReflection Mit Style

// Class with private constructor
function constructor(constructor) {
function Class() {
constructor.apply(this, arguments);
};
return Class;
};

// Class creator
function Class(__proto__) {
function Class() {};
if (__proto__) {
if (hasOwnProperty.call(__proto__, "constructor")) {
Class = constructor(__proto__.constructor);
};
(Class.prototype = clone(__proto__)).constructor = Class;
};
return Class;
};

// special Function
function $Function(arguments, body) {
return this instanceof Function ?
Class(arguments) :
body == null ? Function(arguments) : Function(arguments, body)
;
};

// private variables
var
hasOwnProperty = Object.prototype.hasOwnProperty,
clone = Object.clone || (function () {
function clone() {};
return function (__proto__) {
clone.prototype = __proto__;
return new clone;
};
})()
;

// public static explicit factory
$Function.create = Function;
$Function.createClass = Class;

$Function.prototype = Function.prototype;

return $Function;
})(Function);

Here we are, and the best thing is that we can extend the prototype chain simply passing another prototype as configuration object.

function A(){};

var B = new Function(A.prototype);

alert(new B instanceof A); // true

Moreover, since whatever library will use a Function to create other functions, but since most of the time the new Class won't return an instanceof Class, with my suggestion whatever created "Class" will simply inherit Function.prototype.methods OR, if we want to add custom public methods, we can always do it later.
Finally, with a simple closure, we can still be semantic, and define private methods:

var MyClass = new Function((function () {
function set(value) {
this.value = value;
};
return {
constructor:function (value) {set.call(this, value)},
get:function () {return this.value}
};
})());

var o = new MyClass(123);
alert(o.get()); // 123

Now it's your turn, feel free to comment the path I followed, and give me other suggestions/common errors, if you remember any ;)

Update I almost forgot one of the most famous/silly one ...

Arrays "for in"



var a = [];
a[1] = 1;
a[0] = 0;

// global key defined
for(key in a);

// key will be first 1, then zero, in Internet Explorer and Opera
for(var key in a);

Another common mistake is to think that "for in" is good for arrays.
First of all the iteration order is unpredictable, there is no rule about "for in" iteration (or if any, nothing that is standard, cross-browser speaking) plus it's way slower than a normal iteration via length. Please DON'T!!! In this case as well.

Tuesday, January 12, 2010

ActionScript 2.0 to JavaScript Bridge

As discussed in my new year Ajaxian post, the Flash Player could provide some truly good info about the current user.
I have tried before to create a sort of "perfect bridge" to actually drive ActionScript directly via JavaScript.
Unfortunately, the layer added by the ExternalInterface is not light at all and things would move so slowly that it won't be worth it.
While in my post comments I have showed an example about how it is possible to export info from ActionScript to JavaScript, what I am describing right now is a sort of "general purpose bridge" to bring, statically and stateless, whatever info we need/want from whatever ActionScript 2.0 file/library we like, starting from the root.

Basic Example



<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>AS2Bridge by WebReflection</title>
<script type="text/javascript" src="AS2Bridge.js"></script>
</head>
<body>
<script type="text/javascript">

// override defaults showing the SWF
new AS2Bridge({width:320, height:200, style:""}).onload = function(){
var System = this.retrieve("System");
window.console && console.log(System);
setTimeout(function () {
System.showSettings();
}, 1000);
};

// another movie, an hidden one, just to retrieve some global AS 2.0 property
new AS2Bridge().onload = function(){
var _quality = this.retrieve("_quality");
window.console && console.log(_quality);
};

</script>
</body>
</html>

The AS2Bridge constructor creates each time, and if necessary, an instance related to the current ActionScript 2.0 global scope.

Single Method API: retrieve

Each instance will have a couple of public static properties, as is for example its related object id, plus a single public method:
self.retrieve(namespace:String):Object

Above method accepts a generic namespace string, which is basically the whole path, starting from the root, that will be exported.
This string can point to a property, a generic object, or even a function or method ... does it sound interesting?
As example, it is possible to export the whole System public static object:

var System = this.retrieve("System");

or just one part of it:

var playMusic = this.retrieve("System.capabilities.hasAudio");


The ActionScript 2.0 Code


(function ():Void {
/*! (C) Andrea Giammarchi - Mit Style License */

/** dependencies */
import flash.external.ExternalInterface;

/**
* executes a function and returns its exported value
* @param Number the registerd callback to exec
* @param Array arguments to send
* @return String exported result via callback
*/
function exec(i:Number, arguments:Array):String {
return callback[i].apply(null, arguments);
};

/**
* evaluates a namespace and exports it
* @param String a generic namespace to retrieve
* @return String exported namespace or one of its properties/methods
*/
function retrieve(key:String):String {
return export(eval(key), self);
};

/**
* Exports a generic object injecting its parent scope.
* @param Object generic property, value, method, or namespace to export
* @param Object parent to inject if a method is encountered ( e.g. (o = showSettings).call((p = System)) )
* @return String exported Object, the first argument, JavaScript compatible
*/
function export(o:Object, p:Object):String {
var type:String = typeof o;
switch (true) {
case o === null:
case type === "number":
case o instanceof Number:
if (isNaN(o)) {
return "null";
};
case type === "boolean":
case o instanceof Boolean:
return "" + o;
case type === "function":
case o instanceof Function:
return "function(){return " + bridge + ".__eval__('return '+" + bridge + ".__swf__.AS2Bridge__exec__(" + (callback.push(
function ():String {
return export(o.apply(p, arguments), p);
}
) - 1) + ",Array.prototype.slice.call(arguments)))()}";
case type === "string":
case o instanceof String:
return 'decodeURIComponent("' + escape("" + o) + '")';
case o instanceof Array:
for (var a:Array = new Array(), i:Number = 0, length:Number = o.length; i < length; ++i) {
a[i] = export(o[i], a);
};
return "[" + a.join(",") + "]";
case o instanceof Date:
return "new Date(" + o.getTime() + ")";
case o instanceof Object:
var a:Array = new Array();
var i:Number = 0;
for (var key:String in o) {
a[i++] = key + ":" + export(o[key], o);
};
return "{" + a.join(",") + "}";
default:
return "undefined";
};
};

/**
* Stack of stored callbacks encountered during exports.
* @private
*/
var callback:Array = new Array();

/**
* _root alias
* @private
*/
var self:Object = this;

/**
* String shortcut to use to point to the current bridge object (passed via query string or FlashVar)
* @private
*/
var bridge:String = "AS2Bridge.__register__[" + self.AS2Bridge__index__ + "]";

/**
* unobtrusive exposed callbacks
*/
ExternalInterface.addCallback("AS2Bridge__exec__", this, exec);
ExternalInterface.addCallback("AS2Bridge__retrieve__", this, retrieve);

/**
* JavaScript initialization
*/
ExternalInterface.call("eval", bridge + ".__init__&&" + bridge + ".__init__()");

}).call(this);

// optional stop to avoid loops if/when necessary
stop();

Thanks to a single closure, this snippet is desgned to work as stand alone, or as "general purpose no conflict plugin". In few words, whatever happens in the SWF it is always possible to retrieve a namespace/property/method and it is always possible from the SWF to call JavaScript:

// it is possible to call any public function without problems, e.g.
ExternalInterface.call("eval", 'alert("Hello from SWF")');


The ASBridge Constructor


if (typeof AS2Bridge !== "function") {
/*! (C) Andrea Giammarchi - Mit Style License */
var AS2Bridge = function (options) {
var index = AS2Bridge.__register__.push(this) - 1;
if (options) {
for (var key in options) {
this[key] = options[key];
};
};
this.id += index;
this.src += "?AS2Bridge__index__=" + index;
document.write(document.body ? this.__swf__() : "<body>" + this.__swf__() + "</body>");
};
AS2Bridge.__register__ = [];
AS2Bridge.prototype = {
constructor: AS2Bridge,
id: "__AS2Bridge__",
src: "AS2Bridge.swf",
style: "position:absolute;top:-10000px;left:-10000px;",
width: 1,
height: 1,
retrieve:function (key) {
return this.__eval__("return " + this.__swf__.AS2Bridge__retrieve__(key))();
},
__eval__:Function,
__init__:function(){
this.__swf__ = window[this.id] || document[this.id];
this.__init__ = null;
if (this.onload) {
this.onload();
};
},
__swf__:function () {
return ''.concat(
'<object type="application/x-shockwave-flash" ',
'style="', this.style, '" ',
'id="', this.id, '" ',
'width="', this.width, '" ',
'height="', this.height, '" ',
'data="', this.src, '">',
'<param name="movie" value="', this.src, '" />',
'</object>'
);
}
};
};

I am sorry I had no time to put proper comments, but I think it is simple enough to understand what's going on there.
There are defaults options, plus an horrible document write which aim is simply the one to put the SWF in place avoiding body problems.
Anyway, AS2Bridge would like to be after the head element, possibly inside the body ... the important thing is that it works, so why bother? ;)

The Whole Demo

With 908 bytes of cacheable SWF, and a ridiculous sice for the minified and gzipped JavaScript file, it is possible to test all I have said directly here.

Integration

ActionScript 3 a part, and would be nice to have time to create a bridge for it as well, it is possible to copy and paste in the root of whatever project my AS2.0 code in order to bring ActionScript to JavaScript export capability everywhere.
... told'ya it was something interesting, or maybe not ...

Monday, January 04, 2010

Flash Satay Revisited

The most famous and W3 friendly technique to serve an SWF has been described in this excellent A List Apart Article ages ago. Unfortunately there are few problems with that technique, and being Flash Player still widely adopted, plus nobody has created yet a HTML5 friendly Satay method, here I am with this proposal/suggestion.

Satay Problems

There are at least a couple of problems with the good old Satay method:

  1. double SWF request, performed by almost every browser

  2. SWF impossible to cache, due necessary queryString for each different SWF so that classic c.swf will be required for each call



Object Tag Behavior

The Satay method is based over the assumption that an object tag, with a forced type, will help the browser to recognize the SWF.
At the same time, if Flash Player is not present or it has been disabled, Satay trick allows us to provide an alternative content inside the Object itself.
What we should be aware is that Internet Explorer won't execute any script tag inside the object.
At the same time, Internet Explorer and for some reason Opera as well, is the only one able to recognize and correctly execute the SWF without effort at all.
This is why my proposal relies into JavaScript, excluding Opera from the list of browser that should replace the object tag with the embed one.

Removed Data Property

The reason Satay loads two times the SWF, even if this is executed only once, is the data property. Once it is interpreted, Firefox and every other will understand the object itself and the classic "param name movie" will be re-evaluated. On the other hand, if there is a "param name movie" this is the one used by Internet Explorer to understand which movie should be loaded and interpreted via Flash Player plug-in.
Being this node available for every other browser as well, we can use its value to understand the movie replacing the whole object with an embed that will have the same src.

Alternative Content

If the Flash Player is not present/enabled the script won't perform anything except remove itself from the DOM since once executed, it does not need to do anything else. This means that the browser will simply show the alternative content being unable to understand what kind of object has been encountered, so we still have the nice layout fallback.

WebReflection Solution: HTML5 Layout Example


<!DOCTYPE html>
<html>
<head>
<script>
// generic function to initialize the SWF
function ASReady(msg) {
// IE + Others way to access the SWF exposed properties
(window["my-swf"] || document["my-swf"]).hello(msg);
};
</script>
</head>
<body>
<!--// regular object as if it is for IE/Opera only //-->
<object id="my-swf" type="application/x-shockwave-flash" width="43" height="72">
<param name="movie" value="alert.swf" />
<param name="FlashVars" value="msg=<?php echo rand(0, 100000); ?>" />
<!--// optional stuff to show if Flash Player is disabled //-->
<img src="alert.png" width="43" height="72" alt="" />
<!--// the tricky script, interpreted by every browser but IE //-->
<script src="satay2.min.js"></script>
</object>
</body>
</html>

Above layout passed without problems the W3 validator.
Please note that I am not using the classic query string to understand which file should be eventually loaded but a better FlashVars dedicated param node.
In this way the generic c.swf file can be reused without problems even via absolute url inclusion and finally cached directly via browser.

WebReflection Solution: satay2.js


(function (window) {
// (C) WebReflection - Mit Style License

// let's try to be future proof ...
"use strict";
for (var
// just ashortcut
type = "application/x-shockwave-flash",
// plugins property or ...
plugins = navigator.plugins,
// mimeTypes one
mimeTypes = navigator.mimeTypes,
// this operation should be performed only if it's not opera
enabledPlugin = !window.opera &&
// if plugins exists and "Shockwave Flash" is a valid property
(plugins && plugins["Shockwave Flash"]) ||
// or if mimeTypes plus $type exists and enabledPlugin is true
(mimeTypes && mimeTypes[type] && mimeTypes[type].enabledPlugin),
// grab the current script
script = document.getElementsByTagName("script"),
// set the current script as the last one (normal flow)
// find the parentNode (NOTE: quirks only)
object = (script = script[script.length - 1]).parentNode,
// create the element if necessary
embed = enabledPlugin && document.createElement("embed"),
// find out each param node, if necessary
param = enabledPlugin && object.getElementsByTagName("param"),
// set loop range
i = 0, length = enabledPlugin ? param.length : 0;
i < length; ++i
) {
// for each param, set relative embed tag property
embed.setAttribute(param[i].name === "movie" ? "src" : param[i].name, param[i].value);
};
// only if Flash player is present and enabled ...
if (enabledPlugin) {
// for each object attribute, set it into the embed node (id included, if any)
for (var attributes = object.attributes, i = 0, length = attributes.length; i < length; ++i) {
embed.setAttribute(attributes[i].name, attributes[i].value);
};
// replace the object with the embed node
object.parentNode.replaceChild(embed, object);
} else {
// remove this script, nothing to do
script.parentNode.removeChild(script);
};
})(this);

Via few checks and a couple of loops, above script, about 350 bytes minified and gzipped, will replace the object with the only element able to serve SWFs with browsers such: Firefox, Chrome, Safari, and few others.

WebReflection Solution: AS 2.0 Example

Just for this demo I have created an SWF which aim is to tell us if everything is working properly.

// dependencies
import flash.external.ExternalInterface;

// expose a hello callback to JavaScript.
// this callback accepts a string and it will perform a JavaScript alert
// with the text "Hello! " plus the received string.
ExternalInterface.addCallback("hello", this, function (msg:String):Void {
ExternalInterface.call("alert", "Hello! " + msg);
});

// initialize this SWF calling global JavaScript ASReady function.
// this.msg will be the variable set via FlashVars param
// for this demo, simply a random number generated via PHP
ExternalInterface.call("ASReady", this.msg);

// good old stop(); to avoid loops over the current frame
stop();

You can find a live demo in this page monitoring, or not, network traffic to discover that finally the SWF is requested only once rather than twice.
This should even speed up the execution thanks to non blocking embed.src nature and the missed, useless, second request to the server (a 304 that is still an extra pointless request).

As Summary

If we would like to make markup as clear as possible respecting validation and using all we can use to speed up layout execution, the only MUST for this method is a proper non quirk layout.
In any case, this was the purpose of Satay method as well so, if we liked that one, I am sure we can appreciate mine proposal.

Saturday, January 02, 2010

The Solution Is Simple: Buy A Netbook And Test There!

Something every web developer should do, is test whatever Web related stuff into new generation devices such netbooks, low cost notebook, old PCs and/or smart phones.
If a non techie user surfs a website and the latter one horribly slows down his "device", in the most common case, and specially if the website is "famous", this user will blame its wonderful piece of technology, rather than the infamous designer/developer that created the problem.

This happened recently, as example, in Hotamail and with the latest Sherlock Holmes Flash banner.



The Solution Is Simple

Starting with the fact that Junior Flash developers are as responsible as advertisement hosts, unable to filter proper banners from annoying one, if a company would like to provide these heavy computation banners it should simply make a little investment as a whatever Atom CPU based device is (even just an all in one motherboard is enough!).
Even better, it could recycle a generic good old Pentium III based PC in order to be sure that computation is reasonable, where for reasonable I mean no more than 50% as maximum peak.

As an old ActionScript developer, I've always found disturbing the fact people paid to create ads, are too often unaware of problems they could cause.

I have already commented here or elsewhere old Tiscali or IBM heavy banners, recently improved and much less painful for low cost CPUs, I still find ridiculous that in 2010, the beginning of the mobile and low power consumption era, a good movie as Sherlock Holmes is could be sponsored in such obtrusive way: obtrusive for nowadays net dedicated devices: please change it!

Tuesday, December 22, 2009

JS And CSS3 Snow FX? Happy Holidays!

I was expecting some sort of snow experiment after one of my posts in Ajaxian but apparently nobody tried ... and there I am :)



Check out my JavaScript and CSS3 Snow Effect and have best holidays, I gonna fly tomorrow to meet my family and my friends for few days in Italy!

Friday, December 18, 2009

Leaving London for Berlin - Nokia Gate5

This is just a quick post. First of all, my apologies about my recent absence: you have not even a rough idea about how busy I have been these days ...
Everything is a rush, but if "the rush" is for a good cause it's just a pleasure!
I am organizing my relocation which means I need to close contracts here, flat included, bills, sort out any kind of paperwork I need to leave UK in basically 2 weeks, while I am working, and I still have no idea where I gonna sleep, where I gonna move, but it does not matter: I can't wait to start this new role in Nokia!

Why Nokia

To be honest, I had different choices, but Nokia company in my opinion has been:

Perfectly Organized

When you have to deal with big companies you deal with teams, and in this case I had the opportunity to meet extremely interesting teams and persons while somebody else is not even able to organize their recruitment, putting online "We Are Looking For ..." while they have "all they are looking for" in that moment in the conference, but for another role that does not even match my CV ... FAIL! Big or not, if you have a database it does not matter if somebody has been already interviewed ... isn't it?

Mobile Device Development

It is already the present in USA and it's gonna definitively be the future everywhere.
I cannot take IE and IE6 anymore and moving into mobile where browsers are already better than IE8 and things must be perfect, since the CPU is not powerful, the RAM is never enough, and even the battery life is crucial, can you imagine any other JavaScript sector where every single coma and "var" matters?

Modest and Nice

Even if it's a sector leader, Nokia never gave me the impression they were feeling somehow superior (or that kind of impression such: they are doing you a favor interviewing you ... you know what I mean?)
Trust me when I say that another company "could" ask you during an interview something like: who do you think is the best company in the world?
First of all I do believe that if a company asks these kind of questions it means the company has serious problems ... ask me, whoever you are, which is the best IT company and I will reply in 0.01 milliseconds and as an honest person: Google FFS!!!

Unfortunately, the interview was not with Big G (trust me, I've tried, but they keep ignoring me in London, Victoria ... and moreover, I don't think they actually develop mobile related stuff there ... so you know what? ;) )

Quick

When you are perfectly organized, you are able to do everything instantly and for me this means that a company cares about you and does not have much time to waste with internal bureaucracy: things simply work as expected!

Marry Christmas

This goes to all WebReflection readers, to all Londoners I have met during these 2 years, and to Nokia as well for the kind guide they sent me in order to show me Berlin beauty in English, because there is only one thing I am a bit worried about: I don't know German at all! It's gonna be fun :D

P.S. I am looking for a senior JavaScript to replace me in this current amazing company I am working with - interesting challenging stuff - agile environment - and a new project to manage: leave me a message with your email and a brief description and I swear you gonna like this place in London Bridge: come on guys!

Friday, December 11, 2009

document.write(shenanigans)

As I have twitted yesterday, I have discovered one of the most weird JavaScript behaviors ever thanks to the document.write method.

The Problem We All Know ...

document.write has been used for ages since it is basically the only way we have to create a blocking script during a page download.
The advantage is that a script included via document.write could write something else in that point of the page and again via document.write.
Classic examples are Google AdSense or others similar services where we would like to put in place an iframe with banners or an external service.
The most known side effect of the document.write method is that if the document has been already loaded (DOMContentLoaded or onload event) it could "destroy" our web page erasing everything and showing nothing except what we wrote via this method. This means that every time we include in our page an external resource, we should be sure this resource will be included synchronously otherwise we could break the whole web site showing "blank scripts" and nothing else.

... And The WTF We Should Be Aware About!

Bear in mind:blocking script does NOT necessary mean synchronous.
There are truly few de facto standards about document.write behavior and the only one that seems to be consistent across different browsers is the script without an external source:

<!DOCTYPE html>
<html>
<head>
<script>
var sequence = [1];
document.write('<script>sequence.push(2);<'+'/script>');
alert(document.getElementsByTagName("script")[1].text); // sequence.push(2);
sequence.push(3);
</script>
<script>
alert(sequence); // 1,2,3
</script>
</head>
<body>
</body>
</html>

Everything seems obvious and normal, right? It's NOT!
We need to do a step backward about the document write method ... what does it exactly do?
As example, this is not a valid markup:

<script>
var a = 1;
<script>
var b = 2;
</script>
var c = 3;
</script>

If we assume that document.write is writing the code inside the current executed script tag we are wrong.
This method is basically able to splice the "download flow" inserting everything we write instantly after the current script node.
In other words, with document write we can perform that task able to crash Internet Explorer: append a node after the last one rather than inserting it before the current one, which is the reason you should never appendChild when you add a script node, as example, while you can always insertBefore, specially for these days where everybody is talking about non-blocking scripts.
Let's go back in the first example, OK?
If we analyze that simple HTML page we can easily spot there is only ONE script node. The hard coded alert is there to show that the browser has already put and evaluated a script node that is after. Virtually speaking, this is how the page looks when we use the document write.

<!DOCTYPE html>
<html>
<head>
<script>
var sequence = [1];
document.write('<script>sequence.push(2);<'+'/script>');
// put there and execute then come back in this execution flow ...
sequence.push(3);
</script>
<script>
sequence.push(2);
</script>
<script>
alert(sequence); // 1,2,3
</script>
</head>
<body>
</body>
</html>

If we strip out the write operation nobody in this world would expect a 1,2,3 result when sequence is alerted.
This is already an inconsistent behavior since we are breaking the execution flow adding nodes sequentially after but executed in line.
What we could have expected is a sort of "break this script node, write the new one here, open and go on with the original script".
Well, this makes sense in a global context flow, but if we where inside a nested closure we cannot split the current node or the code will break and the context spread around ... (metaphorically speaking)

... guess what? what I have said so far is the less interesting part ...

External Source Double WTF!

Against every logic we can still assume that a script written via document.write is both blocking and synchronous but things change "a tiny bit" if we write a script node with an src attribute.

<!DOCTYPE html>
<html>
<head>
<script>
var sequence = [1];
document.write('<script src="test2.js"><'+'/script>');
// how cute, the blocking script is already there
// but it is not blocking the execution flow!
alert(document.getElementsByTagName("script")[1].src); // test2.js
sequence.push(3);
</script>
<script>
// indeed!!!
alert(sequence); // 1,3,2
</script>
</head>
<body>
</body>
</html>

What just happened? First of all, the test2.js file is nothing different from:
sequence.push(2);

but the result could sound a bit weird, isn't it?
As I have commented, the script is still a blocking one, in the meaning that after the current script node its content will be available but never before!

<script>
var sequence = [];
// global id
var id = 1;
// test3.js contains the code
//sequence.push(id);
document.write('<script src="test3.js"><'+'/script>');
// global id re-defined
var id = 2;
document.write('<script src="test3.js"><'+'/script>');
</script>
<script>
alert(sequence); // 2,2
</script>

The non blocking external script involves network traffic so every browser vendor decided that a scope cannot be "paused" that long and every browser I have tested confirms the behavior: the current scope has already finished when the injected script will be parsed and evaluated.
The script execution is something performed in the future, not in the current script scope. To put order in this chaos we need to split the script execution flow

<!DOCTYPE html>
<html>
<head>
<script>
var sequence = [];
var id = 1;
document.write('<script src="test3.js"><'+'/script>');
</script>
<!-- the precedent write will put the blocking node here -->
<script>
var id = 2;
document.write('<script src="test3.js"><'+'/script>');
</script>
<!-- the precedent write will put the blocking node here -->
<script>
alert(sequence); // 1,2 in every browser
</script>
</head>
<body>
</body>
</html>


So Why Bother?

Imagine we are doing everything is possible to do to use best practices to speed up our page, avoid network calls, pre-optimize, pre-compile, pre-gzip/deflate a single JavaScript file with everything we want and we need for that page ... well, if for some reason we have a document.write in the middle we will never know what the hell will happen!

var myServiceKey = "I_FEEL_SAFE";
document.write('<'+'script src="myservice.stuff.com"><'+'/script>');
// where myservice.stuff.com will consider the global myServiceKey


// and 2 thousands lines after inside a third part library
// and gosh knows which kind of nested closure is doing it ...
myServiceKey = "HE_FELT_SAFE";
document.write('<'+'script src="myservice.stuff.com"><'+'/script>');


Good stuff, myservice.stuff.com will never know my API, is it cool?

The Long Ride To The Solution

I don't want to create illusions, so I start this paragraph with this fact:
I have not been able to find a reasonable solution!

If still interested, follow me into my "evil monkey patch procedure" ...
First of all, it's a matter of nodes? So, if I create an external node to mess up the execution flow something should happen, right?

<!DOCTYPE html>
<html>
<head>
<script>
function elsewhere(text){
// wuick way to inject script nodes
// to execute on a global context
with(document)
with(documentElement)
insertBefore(
createElement("script"),
lastChild
)
.text = "(" + text + ")()"
;
};
var sequence = [];
var id;
elsewhere(function(){
id = 1;
});
document.write('<script src="test3.js"><'+'/script>');
elsewhere(function(){
id = 2;
});
document.write('<script src="test3.js"><'+'/script>');
</script>
<script>
alert(sequence); // 1,2 in Firefox
// 2,2 in IE, Chrome, Safari
// undefined,undefined in Opera
</script>
</head>
<body>
</body>
</html>

I have basically opened "Hell Doors" with this hack, but trust me, I felt the coolest JavaScript hacker ever when I first tried with Firefox, the only one that gave me the expected messed result. NO WAY, IE, Chrome, and Safari, still respect the order and since the injected global evaluated node is before the one appended in the middle of the browser parsing flow, nothing changes, and it's even kinda expected (I have tried to find out how buggy could have been our browsers).
Apparently, Firefox demonstrates an absolute non-sense: the blocking not synchronous script is still appended but some how it will consider the JavaScript snapshot created via another node as privileged ... I am sure this is a hole in the parser security model but I don't want to investigate more (specially for this topic).
What about Opera 10? Apparently it simply executes the blocking script before the injected one, so some how it has a proper queue and maybe, Opera behavior is the most logical ever: a queue of scripts FIFO style, excellent!

The Evil Plan + A Partial Solution

Still about the assumption that everything is because of the opened/closed script tag:

<!DOCTYPE html>
<html>
<head>
<script>
var sequence = [];
var id;
document.write('<script>id = 1;<'+'/script><script src="test3.js"><'+'/script>');
document.write('<script>id = 2;<'+'/script><script src="test3.js"><'+'/script>');
</script>
<script>
alert(sequence); // 2,2 in IE - 1,2 Others
</script>
</head>
<body>
</body>
</html>

This time the queue is almost respected by every browser, but remember the difference between a script without an external source and one with an external source?
Well, in Internet Explorer the script without an external source is extrapolated from the write context and parsed/evaluated in-line while external source based scripts are still considered "something that will be but that cannot be right now".
There is a perverse logic in this behavior but somehow makes sense from a programming point of view. Not because I agree with what happens in IE, simply because if we have "attached" a behavior, we expect it works just like that ... not everybody is able to think smart, and somehow I can see your faces: nobody surprised IE failed here as well!

The Partial Solution

So IE is the last one, but it is consistent with its crap. This means that we need to put order in the execution flow.
How? Creating two scripts with an external source:

<!DOCTYPE html>
<html>
<head>
<script src="params.js"></script>
<script>
var sequence = [];
document.write('<script src="test6.js?id=1"><'+'/script><script src="test3.js"><'+'/script>');
document.write('<script src="test6.js?id=2"><'+'/script><script src="test3.js"><'+'/script>');
</script>
<script>
alert(sequence); // 1,2
</script>
</head>
<body>
</body>
</html>

In few words we need a sort of clever javascript file able to "understand itself" and at the same time able to mutate run-time global scope variables.
This is the commented content of the test6.js file:

(function (script) {
// a loop is necesary since Opera and IE will
// have already every node in the DOM
// (document.write writes everything in a go
// so everything is already there, id 2,2 indeed if we don't check nodes)
// Firefox and Chrome will consider one script a time
for (var
filter = {id:function(i){return parseInt(i,10)}},
script = document.getElementsByTagName("script"),
i = 0, length = script.length,
tmp; i < length; ++i
) {
tmp = params(script[i].src, filter);
if (tmp.id) {
// let's mark somehow the script so that next loop
// won't consider this one
if (!script[i].touched) {
script[i].touched = true;
window.id = tmp.id
break;
};
};
};
})();

The params function is something I wrote few minutes ago able to transform an url with a query string into an object with key/value pairs:

function params(url, filter) {
// (C) WebReflection params snippet - Mit Style
// create a key/value(s)? object
// with urls query string and optional filters
var query = url.indexOf("?"),
result = {},
key, match, re, value
;
if (query < 0)
return result
;
if (!filter)
filter = {}
;
re = /([^=]*?)=(.*?)(?:&|#|$)/g;
url = url.slice(query + 1);
while(match = re.exec(url)) {
key = match[1];
value = typeof filter[key] === "function" ? filter[key](match[2]) : match[2];
if (result[key]) {
if (typeof result[key] === "string")
result[key] = [result[key], value]
; else
result[key].push(value);
} else
result[key] = value
;
};
return result;
};

Above snippet is the "re-usable for other purpose" content of the params function.
The main side effect of this approach is that rather than speed up the page download we will ask the client browser to download an extra file.
Sure, it can be static, it can be handled via 304, but it is still an extra call to our server.
The good part is that this file could be reused in many situations, the bad one is that is potentially a file we cannot trust, since other scripts could be able to use this file for other purposes ... this is why it is a partial solution, and why I have tried another experiment:

<!DOCTYPE html>
<html>
<head>
<script>
function $write(src, exec) {
var eval = "Function('('+unescape('" + escape("" + exec) + "')+')()')()";
document.write([
'<script src="javascript:void(0)"',
' onerror="',
eval,
'"><',
'/script><script src="',
src,
'"><',
'/script>'
].join(""));
};
var sequence = [];
var id;
$write("test3.js?1", function(){
id = 1;
});
$write("test3.js?2", function(){
id = 2;
});
</script>
<script>
alert(sequence); // 1,2 Firefox, Chrome
</script>
</head>
<body>
</body>
</html>

The problem is that IE won't work, since there is no such onerror handler in script nodes, plus the behavior is not consistent. If we try to reload the page a couple of times, mainly if other files have been cached, we could have randomly 1,2 or 2,2 - at least in Opera so ... experiment failed.

Conclusion

document.write is dangerous! I could not expect all this crap for a single "innocent" function but what I am sure about is that I have never used it, unless strictly necessary (never, imho), and I will try to do not use this method anymore since it causes too many problems, and I cannot even imagine why on earth and how Google, as many others, have been able to handle all their services faking the script injection via blocking writes, and obtaining potentially wrong info and nothing else. Be careful, oops, sorry, I meant ... forget document.write!

Thursday, December 10, 2009

TaskSpeed - The Real Cheat

Inline "make" test that no library should "outperform" - this is a reply to this post which has few good points, we all know about browsers VS SunSpider, and other tests, but it falls down when it criticizes the TaskSpeed aim which is completely different.

"make": function(){
for(var
el = document.createElement("div"),
outperform_this = [],
i = 0, length = 250; i < length; ++i
)
outperform_this[i] = '<ul class="fromcode" id="setid' + i + '"><li>one</li><li>two</li><li>three</li></ul>'
;
el.innerHTML = outperform_this.join("");
for(var i = 0, fragment = document.createDocumentFragment(), childNodes = el.childNodes; i < length; ++i)
fragment.appendChild(childNodes[0])
;
document.body.appendChild(fragment);
if(document.querySelectorAll)
return document.querySelectorAll("ul.fromcode").length
;
if(document.getElementsByClassName){
for(var childNodes = document.getElementsByClassName("fromcode"), length = childNodes.length, i = 0, l = 250; i < length; ++i){
if(childNodes[i].nodeName !== "UL") --l;
};
return l;
};
for(var childNodes = document.getElementsByTagName("ul"), i = 0, l = 0, length = childNodes.length; i < length; ++i){
if(childNodes[i].className === "fromcode")
++l
;
};
return l;
}

Enjoy cheats, and feel cool!

Wednesday, December 09, 2009

Two Step Backward: Read Cookies!

OK, I am the first one with non updated examples in devpro, but today just as curiosity I decided to have a look into every cookie related piece of library.

Apparently to retrieve cookies we have loops, splits, multiple RegExp, and any other sort of alchemy ... but are these functions the only one we need to read cookies?

var Cookie = {
get:function (name) {
var match = document.cookie.match(
new RegExp("(?:^|;\\s*)" + name + "=([^;]*?)", "g")
);
return match && match[1];
},
getAll:function () {
var re = new RegExp("([^=]+?)=([^;]*?)(?:;\\s*|$)", "g"),
cookie = "" + document.cookie,
result = {},
match
;
while(match = re.exec(cookie))
result[match[1]] = match[2]
;
return result;
}
};

I think sometimes we overload methods without a valid reason, but maybe I am missing something ... the only option I could eventually spot is the encode/decode, but as far as I know that is a browser problem, is it?
If we need that, well ...

var Cookie = {
get:function (name, encoded) {
var match = document.cookie.match(
new RegExp("(?:^|;\\s*)" + (encoded ? encodeURIComponent(name) : name) + "=([^;]*?)", "g")
);
return match && decodeURIComponent(match[1]);
},
getAll:function (encoded) {
var re = new RegExp("([^=]+?)=([^;]*?)(?:;\\s*|$)", "g"),
cookie = "" + document.cookie,
result = {},
match
;
while(match = re.exec(cookie))
result[encoded ? decodeURIComponent(match[1]) : match[1]] =
encoded ? decodeURIComponent(match[2]) : match[2];
;
return result;
}
};

Tuesday, December 08, 2009

Bing UK - Round 2

I've been contacted for the second time by Jordi Ribas from Bing.com but this time for a one to one chat rather than just a Round Table.

First of all, even if I keep thinking why on earth they would like to know my opinion, I do appreciate the fact Microsoft teams are getting closer with developers as well (the problem is: do they know I am a web developer and not a web surfer?)

One Hour Chat

Nothing more and quite frenetic: I had a lot of questions while Jordi had to show me improvements since first disaster where they introduced bing UK showing us the USA version ...

Different Teams

Apparently Team System is not that powerful as we think. Microsoft teams are not sharing realtime code or improvements. There is a delay, that could be few days up to few months between USA and other versions and every team seems to be in charge of proper country search algorithm ...
In my opinion this is a massive waste of resources for whatever IT company. The team knowledge is partially sandboxed, but this is what we expect from whatever Microsoft product, but even strategies are different.
As example, bing USA shows useful info about whatever city plus touristic stuff and much more. Try to look for Chicago in bing USA and first info will be both useful and well organized: nice.
After 30 minutes of "look how much we take care about UK results" we tried London and not a single weather, map, or useful info has been showed. Even cooler, the first sponsored link is called: The Fastest Way To France ... I mean, Doode, if you search London of course it's because you wanna escape!

Visualize Mode - Aka Silverlight

Apparently Bing team put a lot of effort into visualize section ... what, you cannot use it?
Well, in my PC I have Flash, Silverlight, Java ...

So what? I do NOT
Jordi is a nice guy but he lost 300 points out of 10 when he replied something like:

JavaScript? ... ah, I am big fan, one team long time ago did this stuff and they used ECMAScript ...

Say what? In few words I had to show a truly silly example explaining that if I've been able to do that kind of FX via 1.23 KB of JavaScript, there is absolutely nothing, I repeat: nothing that is not possible to replicate in that visualize page via JavaScript rather than require a plug-in that is Microsoft specific.
He was surprised:
Did you really do this? ... oh yes, your name is there ... really it is only JavaScript?

(... I mean, guys, if you don't even know who you are inviting please don't ...)

Anyway, after this He talked about some standard stuff and I almost flipped out: so, Silverlight is considered a standard in Microsoft while JavaScript is considered "the old ECMAScript somebody tried ages ago" ... so, now my eyes are opened ... they don't even know they are using JavaScript in the whole site and partially even in the Silverlight section (images fade in/out FX) ... uhm ...

Why Silverlight

The only reasonable answers I've had about Silverlight are:
  1. we could not obtain same performances
  2. it's Microsoft stuff
In few words, Microsoft spent years and money to create a plugin able to bring what whatever TraceMonkey, V8, or WebKit based browser can devour with closed eyes. The day Microsoft will realize that the reason is loosing market share is an historical software cancer called Internet Explorer will be too late, surely after Google will beat everybody with free wireless access and free operating systems virus free and created to be online 100% of the time.

We Are Morons

I have tried to surf Bing via my Android ... slow, too slow, plus I need to move the page around to perform a search. What I have asked was:
Is there any chance you will put in the preferences panel a checkbox able to remove all that layout since the reason I use a search engine is to search stuff rather than check, as example, info about a Zebra mouth?

The answer was something like:
You see? When we have been in a school the Teacher was asking kids about those info showed over home page images!

There we are, the we are all morons Microsoft style is another reason developers do not always appreciate Microsoft decisions.
In few words Bing has been created for kids. OK, nice try, good purpose, I am sure we all wanna know more about the Zebra, but can it be possible that me, as 31 years old man that was only trying to search something had to wait 175 Kb before I can perform a search via suggestion and other more useful stuff? Can I decide to be interested about the Zebra mouth, only when I search for it? Maybe I am asking too much consideration ... so why does not Microsoft provide a teacher for all of us, interviewing about whatever bing shows in the home page?

Mobile Device Version

Since an average of 175 Kb plus a layout created for massive images, "let me suspect" that Bing did not think at all about all current and new Smart Phones (too futuristic, isn't it?), I have asked if there was any plan for a mobile version since that layout was clearly too much for my Android.
He showed me a weird phone I have no idea about, plus an address: m.bing.com
Well, the m.bing.co.uk is just bing but remember the "we don't share code and knowledge" strategy? USA did a step forward providing this smart, fast, simple, and efficient interface and only in 4 Kb ... I already love this version!!! I would like to spend more time about this super fast and efficient Bing but I have been called for something else ... the "for kid and broadband only" version ... how cute!

Partially Color Blind

Both first time and this time I had to underline it's difficult and confusing for me to have all these bloody random images under main features on the top left of the page.
This is the main reason I have asked if it was possible to remove from preferences panel these pointless images since I am not interested but all I received as answer was something like:
We have a blind developer that is complaining more about tags positions

So, since I am extremely lucky compared with this person, I can be ignored ... my problem does not exist, right?
FAIL, let me remove those bloody thingy under what I am trying to read!
Microsoft has always been closed to assisted technologies so why this Bing cannot be "simply simpler" and closer to me as well?

Conclusion

For the good part I let you discover what UK team has done so far. Definitively Bing UK improved from the first beta that was a graphic wrapper around Live, but it's still not that clever as is the USA version and adopted strategies/choices are arguable.
Silverlight: get out my view! Google success is speed and simplicity and Bing best feature requires a third part plugin that could not be there? FAIL
Images: nice, cool, good hint for people that have nothing to do and lot of time to play looking for squares over those images ... but maybe somebody else is trying to work with his/her PC and all this stuff becomes just annoying. I mean, even random images ...
Mobile: if there is a mobile version I expect a massive GO MOBILE button ... where is it, exactly? Not there plus no automatic redirect, and best of all, m.bing.usa is a completely unknown alternative. Microsoft, what are you exactly doing there? We are basically in 2010, did you realize this?

Sunday, December 06, 2009

mjst - Micro JavaScript Template Engine

This is the content I've written so far in the official mjst repository. I'd love to know your thoughts about this little experiment, cheers!

What

mjst is a lightweight, about 1Kb minified and gzipped, and performances focused template engine with standards support. There are dozens JavaScript? Template Engines solutions out there but as far as I know this is the only one based on validation for both client and server side programming languages.

How

There is one single function to call:

// via text (e.g. Ajax or innerHTML from a template node)
var transformed = mjst('<?js var hello = "mjst!"; ?><js-hello/>');

// classic template node example
<script id="mytpl" type="text/html">
 
<?js
   
var hello = "mjst!";
 
?>
 
<js-hello/>
</script>
myEl.innerHTML = mjst(document.getElementById("mytpl"));

/
/ via XML (e.g. Ajax or a created document)
// this is a configuration object as second argument example as well
myEl
.innerHTML = mjst(
 
new DOMParser().parseFromString(
   
'<root><js-hello/><br class="${myBrClass}" /></root>',
   
"text/xml"
 
), {
    hello
:"Hi there!",
    myBrClass
:"clear-both"
 
}
);

// Ajax example with an XML template as response
/*
<root>
  <ul>
    <?js
      for(var i = 0; i < collection.length; ++i) {
    ?>
      <li class="li-${i}">Item No: <js-i/> Name: <?js print(collection[i]); ?></li>
    <?js
      }
    ?>
  </ul>
</root>
*/


// transformation ...
myEl
.innerHTML = mjst(xhr.responseXML, {collection:["a", "b", "c"]});

It is possible to write whatever we want inside an mjst template block via print(1, 2, 3, N, func(), whatever) function, the only one injected in the execution scope.

JavaScript? block VS Attributes

To make mjst templates XML compatible I decided to remove JavaScript? block inside attributes. It is still possible to access JavaScript? variables via ${myVar.propName} as showed, as example, in the br node class.

PHP And JavaScript? Template Example

<?php // mjst example
function mjst($name, $value){
    echo
'<?js var ', $name, '=', json_encode($value), ' ?>';
};
header('Content-Type: text/xml');
$a = array(
    'some database result' => array(1, 2, 3),
    'some other value' => 'Hi There'
);
?>
<?xml version="1.0"?>
<root>
   
<?php mjst('result', $a); ?>
   
<?js
   
for(var k in result)
       
print(result[k], "<br />")
   
;
   
?>
</root>

<script type="text/javascript" src="mjst.js"></script>
<script type="text/
javascript">
onload
= function(){
   
with(this.XMLHttpRequest ?
     
new XMLHttpRequest :
     
new ActiveXObject("Microsoft.MSXML")
   
){
      open
("get", "mjst.php", true);
      onreadystatechange
= function(){
       
if(readyState == 4)
          document
.body.innerHTML = mjst(responseXML);
       
;
     
};
      send
(null);
   
};
};
</script>

Why Standards

Apparently every other JavaScript? template engine is implementing a manual, char by char, or RegExp? based, parser, over a syntax that in PHP world has basically defined deprecated ages ago: the classic <%=stuff%> (<?=stuff?> in PHP). The first reason to avoid this kind of syntax is ambiguity. Which program language should consider that block of code? PHP, ASP, JavaScript? ... who else? Moreover, to make things as clear and simple as possible, avoiding ambiguity, PHP community decided to solve the classic <?xml?> problem, caused by short code block, via an explicit <?php ?> which is the suggested, default one. This is also standards safe, in the meaning that a nodeType 7 is defined as a PROCESSING_INSTRUCTION_NODE In few words mjst is compatible with both valid XML and XHTML, which means that its templates can be created via standard DOM API being sure the template will be valid as well. At the same time, using official engines to validate and parse templates blocks mjst could be considered more reliable than other solutions, more robust, and at the same time fast, thanks to core functionality. The good part, at least for me, is that delegating templates parsing operations to the browser core, is more probable that the error is inside a non valid template block, rather than inside this tiny library source code: a welcome side-effect about standards and core validation.

Why Fast

Every transformation could create one or two pre-compiled functions reused every time we would like to transform an already parsed template block. The reason mjst creates up to two functions is that we can arbitrary send a second argument as configuration object. Since this procedure requires the usage of the with statement, avoiding outer scope name conflicts during the execution, and since we do not necessary need to send this second configuration object, the runtime compiled function will consider both cases, only when encountered, making the with free execution 3 to 10 times faster. In other words, if we transform the same template block always without the second argument, the function that will contain the with statement will never be created and vice versa.

Why Robust

The XML core parser and transformer is also another reason to consider mjst both fast and reliable. As example, probably the most famous JavaScript micro templating, from John Resig, is surely lightweight, but it could suffer some problem if the template block is not perfect. For instance, try to use a string like s = "<%" for whatever reason, and you'll be able to break the John micro suggestion, but this is not only about John code. Another well known product is the EJS library, adopted in many different environments and definitively a good piece of code. EJS offers somethng more than mjst but it is still based on manual parsing over a syntax that XML does not like that much. This means that we could have hard life to generate EJS templates via server or directly in our page while mjst delegates template validity to the markup itself.

<?xml version="1.0" ?> 
<script id="mytpl" type="text/html">
 
<!-- msjt accepts valid XML (as XHTML as well) or HTML5 -->
 
<?js
   
var hello = "mjst is here!";
 
?>
 
<js-hello />
</script>

Why ... Generally Speaking

I am a PHP developer, before being a JavaScript? one, and I have always complained about the open close everythere PHP style. This technique does not split presentation and business logic layers and it is generally "slower than a single echo". I have started to appreciate the couple XML and XSL-T years ago but XSL-T sometimes is just a pain in the ass and via server is difficult to cache XSL-T instances. As example, the New York Time had to create their own core library to speed up transformations over common XSL files allowing fast serialization. Brilliant, but still this ad hoc library does not scale for the whole World Wide Web scenario. Different hosts, different PHP versions, but at the end of the day, what could happen if we delegate the transformation to the client side via core JavaScript? features? Nothing bad, actually it's almost a year I am transforming complex layout into html in the fastest way ever even in IE6 and only thanks to XSL-T but, as I have said, the XSL syntax could not sound familiar at all, specially for programmers that would like to have much more power while they generate a layout. This is basically the reason PHP had such great success over these years, so why don't try to emulate XSL bringing there directly JavaScript? rather than XSL syntax, and in a PHP familiar style? This is all about this experiment. It delegates layout render into the client side, the best place imho to do this. It avoids useless server side stress, it could be embed in the page thanks to the fake script with an unknown type, and as side effect, it could speed up client server interactions re-using templates blocks whenever we need and requiring only data, which nowadays, it is just all we need to make Web users happy. So, as pure final evil plan, we could create a view able to produce mjst templates directly via CouchDB resolving some greedy map reduce operation in the db moving partial logic in the client via simple row data sets or generating clear layout directly via Server Side JavaScript? so that all we need is a language, rather than 3 different technologies ... does it sound insane? ;-)