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

Wednesday, April 22, 2009

Internet Explorer with V8 Engine :: A Partial Reality

Update now it works with Internet Explorer 7 and 8 with O3D plug-in enabled.

Today, via ajaxian, I discovered the new Google O3D project and as a nerd first, and a developer after, I instantly read the API.
Few seconds and I spot this: Use the V8 engine

OK, OK, whatever code you read there will not instantly work ... you have to understand the library and how to retrieve the dreamed eval function to make JavaScript execution possible inside the extremely fast V8 engine.

Obviously V8 integration is great with FireFox and other browsers, but a bit different in Internet Explorer.

This limitation is about the DOM manipulation, something that would make IE a good browser, but everything else, executed via V8 engine and without browser engine references, will perform 5 to 100 time faster.

Function creations, optimized loops, numbers, string manupulation, etc etc ... if we could use a little plugin to fully integrate V8 inside Explorer, we could all forget nowadays benchmark because it will perform better than many other browsers!

Bearing in mind the relationship between V8 variables, different 100% from JScript vars, and latter variables, we can delegate computational tasks to this engine makin IE fast as it has never (and will probably never) been!

What I have so far, is just a poor example about V8 inside IE possibilities, a page that does not work if you do not have V8 inside Exlorer and you do not enable its usage everywhere.

Write a loop like this in the textarea:

for(var a = [], i = 0; i < 500000; ++i)
a[i] = Math.random();

and switching between default and V8 you can read that the difference is about 5 times slower with the default Internet Explorer JavaScript engine, and Google V8.

Still, so far what I can spot as pros and cons is this:
Pros

  • mathematical operations up to 100 times faster

  • computational functions speed up

  • common AI patterns (AStar) finally usable in the web

  • games, chess, cards, whatever involves logic, speed up



Cons

  • even if you assign a V8 Array.prototype.forEach to native Array.prototype.forEach, the plugin cannot solve engine related dependencies problems ... so it will be simply slower, much slower, because of the data interchange between the method executed externally, and the original engine

  • DOM is not integrated, V8 in IE does not understand nodes so no way to speed up common libraries or add prototypes to native HTMLElement constructor

  • last, but not least, with my laptop I cannot even test the example page I posted before because the JS is not that perfect (Google guys, makeClients accept an id but you check .id === "o3d" in the loop ... does it make any sense?) and my card apparently does not support OpenGL or whatever library the o3d plugin requires



As Summary


This was just a quick post and an experiment which in my opinion is already god enough. I have a vision, about Internet Explorer 8.1 ... those guys created an April fool that is everything but not a fool. Come on Microsoft, let others replace your old, problematic, slow, JScript engine, and let us developers be free to create Web Applications as we would like to do ... please give to Google whatever they need to make V8 IE integartion possible, and let us dream about a not that far possible Web future!

Monday, April 20, 2009

Last Minute - Blogger and Spam Blogs

Nice one, 10 minutes after I published my last sarcastic comment about IE sort implementation, blogger sent me an email communicating that my blog has been marked as a spam blog. I am sure if I was an X-Files actor I would have though instantly about conspiracies or some sensible M$ engineer move ... but as web developer and experienced programmer I am sure it is a coincidence and any software is perfect: it does not matter who is behind that software!

P.S. ok, an entry for this fact is probably too much but if you find something weird please be patience, I should be back soon ;)

Sunday, April 19, 2009

Internet Explorer and its inefficient sort implementation

This is just a quick post about how much IE team cares about JavaScript performances ...

// generate an array of 1000 elements
var a = new Array(1000).join(",.").split(","),
calls = 0;

// call sort method incrementing the conter
a.sort(function(a, b){
++calls;
// return zero, nothing should change
return 0;
});

// discover the monster
alert(calls);

Guess how many times Internet Explorer compare results? 17583 times, against a.length - 1 in other browsers.

Nice stuff guys, I guess for big arrays a manual reimplementation could perform better, am I wrong?

[COW] A Generic ArrayObject Converter

Few days ago I wrote about a fast Array slice implementation for every browser, a callback able to convert "every collection" into an Array.
For collection, I mean every instance with a length attribute and an index access Array like. This object, for example, could be considered as a collection:

var generic = {
length: 2,
"0": "abc",
"1": "def"
};

Above instance is a basic model of most common libraries such jQuery, prototype, base, and every other based over an Array like prototype.

Some library could coexist in the same page without problems but not every library implement a method to create a copy of another collection into a new instance of the library itself.
As example, a jQuery or Sizzle result into another instance, a generic DOM collection into a jQuery object, etc etc.
All these instances could be passed via Array.prototype.push to be populated, and thanks to this peculiarity we can obtain every kind of instance from a collection via Array conversion.

var toArrayObject = (function(push, e){
// WebReflection - Mit Style License
e.base = {length:0};
e.slice = (function(slice){
// portable slice
try {
slice.call(document.childNodes);
var $slice = slice;
} catch(e) {
var $slice = function(begin, end){
if(this instanceof Object)
return slice.call(this, begin || 0, end || this.length);
for(var i = begin || 0, length = end || this.length, len = 0, result = []; i < length; ++i)
result[len++] = this[i];
return result;
};
};
return $slice;
})(Array.prototype.slice);

// prototype ready callback
return function(constructor){

// assign the "class" prototype or the base object
// as anonymous prototype
e.prototype = constructor ? constructor.prototype : e.base;

// create a new instance of anonymous
var r = constructor === Array ? [] : new e;

// inject via push the collection, passed as function scope
push.apply(r, e.slice.call(this));

// return the new ArrayObject instance
return r;
};
})(
Array.prototype.push,
function(){}
);

With above code we could quickly transform, for example, a DOM collection into a jQuery instance without using the jQuery engine:


var result = toArrayObject.call(
document.getElementsByTagName("div"),
jQuery
);

result.remove();


Another example could be a transformation between jQuery and prototype:

var prototyped = toArrayObject.call(jQuery(".test"), $);


The same could be obviously done via Array, even if this is a non-common case:

toArrayObject.call([1, 2, 3], jQuery);
toArrayObject.call(jQuery(".test"), Array);


The usage of call makes prototype assignment that simple:

jQuery.fn.convertTo = toArrayObject;

// as prototype or other library conversion
jQuery(".test").convertTo($);


That's it, if you never wondered about elements injections, libraries conversions, or Array like object management, this code could be a truly quick and portable solution.

Tuesday, April 14, 2009

Essential Selector - Cross Browser LightWeight Selector Engine

Thanks to new DOM methods introduced recently in most common browser, e.g. querySelectorAll, we will not hopefully need full libraries to implement common CSS selectors. Nowadays, this could be the basement to create any kind of selector engine but we are still stack with old fashion browsers a la Internet Explorer version 6 or 7, both far away from W3 standards and with the slowest JavaScript engine in browsers panorama.

At the same time, whatever great selector API/engine we have under control, most used selectors are really few:

  • #id

  • .class

  • tag

  • tag.class



Reasons behind this fact are different, but in my opinion the most valid one is that Web Developers use CSS selectors in the same way they create CSS files and since CSS has become standard only recently thaks to Internet Explorer full CSS 2.1 support (n.d. other browsers are working on the CSS 3 since ages ...) our CSS files and our selectors will be that simple for long time.

Accordingly, and since we have some intermediate and cool prototype such getElementsByClassName, all we could need is just a basic selector engine able to retrieve nodes in the fastest possible way.

Of course, if querySelectorAll is present, this method will be a must, but what if it is not available?

Sizzle library is one of the most famous selectors engine so far, but we need "to move" 4KB of minified and gzipped code (not that much but often more than necessary) to obtain something simple, specially if precedent selectors are the only one we use in our project.

The Essential Selector Library

Maybe it sounds obvious, but to cover first 3 selectors in the list all we need is the fast getElementById, the standard getElementsByTagName, and the un-standard getElementsByClassName, easy to implement for old browsers. querySelectorAll? Superfluous in this case, but obviously still welcome! Above 4 selectors are the only one considered for performances in my last tiny library: about 1Kb minified and gzipped, suited for libraries and/or GUI development.
You can have a look directly in my repository to understand what will perform truly fast in every browser and what will perform in a reasonable time.

Essential Selector Philosophy

#id, .class, tag, and tag.class selectors will be fast for every browser while more complex selectors will be browser dependent. The main focus is into most used selectors but if you decide to use a specific one:

// CSS selector example
$e("div ul.myclass p");

recent browsers will perform in about 1 milliseconds while old browsers will perform a clean runtime CSS specific modification. This means that these browsers will have approximately the same delay for a selector like "div p" and "div p #content ul li.testcase" but at least, if the selector is compatible with the browser CSS engine, the result will be the same for every browser.
Moreover, due to the light size of the library, those bugged browsers will not be perfectly supported. As example, thre is a version of Opera which does not understand className in upper case ... well, this is not our problem, it is a browser specific bug so the browser vendor should solve it. The same is for other weird cases ... come on, we cannot consider every alpha/beta/unstable/intermediate/old version, so if the CSS works, the browser will respond as expected.
This is the philosophy behind this simple selector engine, where a search like

$e("div p")

will make sense, while another one like

$e("div[class^=whatever]")

will not, because of the not yet that standard chose selector.

Summary

Do you want a small footprint selector which works OK with daily basis environments? Try out Essential Library, otherwise I just gave you a valid, full compatible, alternative ;)

Wednesday, April 08, 2009

WebReflection PureDom baseline for TaskSpeed

I just had a quick and nice chat with Peter E Higgins and I am proud to announce that my PureDom test has been integrated into TaskSpeed test suite.

Why PureDom

We all know how many benefits libraries give us on daily basis about Web 2.0 supersonic development, but as both libraries author and users, we should pay attention.
Web Developers: sometime we delegate to our cool library some simple task which could be easily implemented manually. If performances are a problem we should use libraries only when and if necessary. There are a lot of best practices for each library and all we need to do is to read these practices to be sure our way to code is of course elegant, but not silly.

// this is silly
$("#items li.selected").each(function(){
$(this).css("color", "red");
$(this).css("background", "blue");
$(this).width($(this).parent().width());
});

// ... while this makes sense
$("#items li.selected").each(function(){

// cache the magic object
var $this = $(this);

// use full lib features, avoid redundant code
$this.css({color:"red", background:"blue"});

$this.width($this.parent().width());
});


Libraries Authors: our main purpose is to define a standard within the library logic and behavior to obtain best "results in zero efforts". Sometimes we could think about light layers between our super cool high level method and pure DOM in order to preserve performances for basic tasks. We all know the most problematic and slow browser, version whatever, is still Internet Explorer, and obviously more we overload the library for this browser, worse the latter one will perform. I hope the PureDom baseline will help all of us to compare results, specially for simple tasks where even the code size is not that different between the chosen lib and the manual DOM execution.


Tricky Monkey, but this is NOT "Python vs ASM"

I know some PureDom task could be interpreted as a "cheat" but honestly, what I have done, was simply follow instructions to create the result. That is my meaning of manual task implementation, and that is why libraries will have hard time against first column. It does not matter if libraries are slower than pure DOM, and it is quite obvious they will be slower, but more these libraries will be close to DOM results more advantages we will have using that library rather than the other one (more competition as well and we like it!)

Have fun with Web development and JavaScript! ;)

Tuesday, April 07, 2009

JavaScript Static Collection - A New Type Of Variable

Nowadays, I am working over a crazy manager between an XML with form information, another XML with custom rules to drive the XML with form information (DropDown onchange events, validation, and much more) and both to drive a runtime Ext.form.FormPanel with runtime components manipulated runtime via those two XML and over regular (x)HTML ... a runtime nightmare, but it is not the point.

While I was working over an Easy XPath Library for (x)HTML, trying to obtain best performances with the black sheep Internet Explorer, I ended up in an msdn page which explains the attributes HTML Element property.

Funny enough, that kind of property has truly a weird behavior, it is between VBScript and JavaScript. There are two ways to access its key/value pairs, the normal and logical one, plus the WTF!!! one. Example:

for(var
attrs = document.body.attributes,
len = attrs.length,
i = 0;
i < len;
++i
)
attrs(i) === attrs[i]; // true

The first though was: damn it, somebody poisoned my coffee again! (where the first time was when I read about Microsoft adopting WebKit as browser engine ...) but after few millisecond of brain delay, I realized that was brilliant!

The StaticCollection Type


Every Function in JavaScript has a length property, which tell us how many arguments that function accepts. In a completely dynamic language as JS is, this property has probably never been used, specially because every function has an ArrayObject arguments variable injected for each function call (but I guess would be interesting to use checks like: arguments.length > arguments.callee.length, for secret extra arguments to send ... anyway ... ).

Peculiarity of this property, we cannot overwrite it!
In few words, it is possible to create an Object via Function with immutable access over a collection, array, ArrayObject variable. This is the code:

var StaticCollection = (function(
name, // function name to assign
join // toString method from Array.prototype
){
// (C) WebReflection - Mit Style License
return function(){
var args = arguments, // trap sent arguments
length = args.length, // just a shortcut
i = 0, // used to assign values in order
callback; // Function to create and return
eval(
// create a function with a $name and $length arguments
// to block its length property
"callback = function ".concat(
name, "(",
new Array(length + 1).join(",$").substring(1),
// return first sent key from external arguments
"){return args[arguments[0]];}"
));
// assign in order properties via index ([0], [1], etc)
while(i < length)
callback[i] = args[i++];
// set the name for those browser where
// the function name is not present (mainly IE)
callback.name = name;
// set the useful toString method
callback.toString = join;
// return the FunctionObject
return callback;
};
})("StaticCollection", Array.prototype.join);

Due to fixed length behavior, the evaluation is absolutely necessary but not scary at all, since the string does not contain anything important, it is a simple wrap.
For those in Rhino or with some arguable rules about eval, here there is the intermediate step via Function:

...
i = 0,
callback= Function(
"args",
"return function ".concat(
name, "(", new Array(length + 1).join(",$").substring(1),
"){return args[arguments[0]];}"
)
).call(this, args);
...

which result is exactly the same but with a little bit of overhead caused by useless runtime Function execution.

StaticCollection Goals


  • one variable with static properties access plus indexed

  • indexed and called properties are comparable

  • indexes are mutable, perfectly suitable for relations between different objects/nodes/values

  • is the only quick and dirty way I know to make a collection immutable

  • something else, you'll find out :D



The StaticCollection Weirdness In Action


// Creation: same result
var sc1 = new StaticCollection("a", "b", "c"),
sc2 = StaticCollection("a", "b", "c"),
sc3 = StaticCollection.call(this, "a", "b", "c"),
sc4 = StaticCollection.apply(this, "abc".split(""))
;
/** [sc1, sc2, sc3, sc4].join("\n");
a,b,c
a,b,c
a,b,c
a,b,c
*/


// Properties Access
var sc = new StaticCollection("a", "b", "c")
sc(0); // "a"
sc[0]; // "a"
for(var key in sc){
key; // "a"
break;
};


// Immutable Properties: length + access via call
var sc = StaticCollection("a", "b", "c");
sc.length = 0;
sc.length; // 3
sc(1); // "b"
// sc(1) = 123; // error!


// Multiple access manifest
var sc = StaticCollection(456);
sc[0] === sc(0); // true
sc[0] = 123;
sc(0); // 456
sc[0]; // 123
for(var key in sc)
sc[key] !== sc(key); // true


// Type: function
typeof StaticCollection(1,2,3);


// Native toString: [object Function]
Object.prototype.toString.call(StaticCollection());


// Array Convertion:
var sc = StaticCollection(1,2,3);
sc.slice = Array.prototype.slice;
var a = sc.slice();
var b = Array.prototype.slice.call(
StaticCollection(4, 5, 6)
);


// Index Sort
var sc = StaticCollection(2, 1, 3);
sc; // 2, 1, 3
sc[0]; // 2
Array.prototype.sort.call(sc, function(a, b){
return a < b ? -1 : 1;
});
sc; // 1, 2, 3
sc[0]; // 1
sc(0); // 2


// Double indexOf
StaticCollectionSearch = function(value){
for(var
result = [-1, -1],
length = this.length,
i = 0;
i < length;
++i
){
if(this(i) === value){
result[0] = i;
break;
}
};
for(i in this){
if(/^\d+$/.test(i) && this[i] === value){
result[1] = i >> 0;
break;
}
};
return result;
};
var sc = StaticCollection(2, 1, 3);
Array.prototype.sort.call(sc, function(a, b){
return a < b ? -1 : 1;
});
StaticCollectionSearch.call(sc, 1); // 1, 0


// Array prototypes behaviour example
var sc = StaticCollection(1,2,3);
Array.prototype.shift.call(sc);
sc; // 2,3,
sc[0]; // 2
sc(0); // 1
sc.length; // 3


Crazy enough? The manually minified version is under 300 bytes, so let's start to play with ;)

/*WebReflection*/(function(n,j){this[n]=function(){var a=arguments,l=a.length,i=0,f;eval("f=function "+n+"("+new Array(l+1).join(",$").substring(1)+"){return a[arguments[0]]}");while(i<l)f[i]=a[i++];f.name=n;f.toString=j;return f}})("StaticCollection",Array.prototype.join);

Have fun!

Friday, April 03, 2009

A fast Array slice for every browser

It is an extremely common task and one of the most used prototype in libraries and applications: Array.prototype.slice
The peculiarity of this prototype is to create an Array from an Array like Object such arguments, HTMLCollection, other kind of lists as jQuery results.

Every browser, except Internet Explorer, allows direct calls via native prototype obtaining, obviously, best performances.

In IE, we have different ways to make this task possible, and these ways are mainly classic loops, or the isArray check to know when it is possible to perform the native call or not.


isArray = (function(toString){
return function(obj){
return toString.call(obj) === "[object Array]";
};
})(Object.prototype.toString);

Even using a closure, above function could slow down performances, specially in those libraries where Array conversions are performed almost everywhere.

As we all know, Internet Explorer behaves weird "sometimes", and one of the weirdest things is that native Objects are not instanceof Object.

In few words, instead of call a function to define if native slice could be applied, all we need to do is to check if the generic object is instanceof Object.
In this way native Arrays, arguments, everything with a length user defined, will be passed via native Array.prototype.slice, while for native objects, the good old loop will do the dirty job.

A better general purpose slice

$slice = (function(slice){
// WebReflection - Mit Style License
try {
// Chrome, FireFox, Opera, Safari, WebKit
slice.call(document.childNodes);
var $slice = slice;
} catch(e) {
// Internet Epxlorer
var $slice = function(begin, end){
// false with native objects/collections
// suitable for Array like Object (e.g arguments, jQuery, etc ...)
if(this instanceof Object)
return slice.call(this, begin || 0, end || this.length);
// ... every other case ...
for(var i = begin || 0, length = end || this.length, len = 0, result = []; i < length; ++i)
result[len++] = this[i];
return result;
};
};
return $slice;
})(Array.prototype.slice);

Simple, isn't it? And here a test case:
(function(){
try {

// HTMLCollection [object, ...]
$slice.call(document.getElementsByTagName("*"));

// arguments [3,2,1]
$slice.call(arguments);

// Array [1,2,3]
$slice.call([1,2,3]);

} catch(e) {

// should never happen
alert(e.message);
};
})(3,2,1);

where if nothing happen, simply means $slice worked without problems.

Side effects? With sandbox variables (iframes) IE will always use the loop, unless we do not bring its native Object constructor into the function (or the function into the sandbox)

Wednesday, April 01, 2009

TaskSpeed: DOM VS Libraries

I tried to create an essential library to perform a manual implementation of the TaskSpeed test suite and results surprised me.

All these web 2.0 libraries are extremely useful, cool, time-saving, whatever you want, but not a single one can compete with manual tasks implementation, specially when we are talking about the most common browser which at the same time is the slowest ever: Internet Explorer!


Final Results for an Dual Core under Windows XP SP3


FireFox 3.0.8
------------------------
library | ms
------------------------
DOM 383
plugd-a (Dojo) 734
Dojo 1.3.0 742
Dojo 1.2.3 1008
MooTools 1.2.1 1252
jQuery 1.3.2 1935
jQuery 1.2.6 3518


Safari 4 Beta (528.16)
------------------------
library | ms
------------------------
DOM 118
plugd-a (Dojo) 170
Dojo 1.3.0 186
Dojo 1.2.3 342
MooTools 1.2.1 347
jQuery 1.3.2 602
jQuery 1.2.6 1025


Opera 10.00 alpha
------------------------
library | ms
------------------------
DOM 111
Dojo 1.3.0 251
plugd-a (Dojo) 374
MooTools 1.2.1 688
Dojo 1.2.3 938
jQuery 1.3.2 1329
jQuery 1.2.6 2327


Internet Explorer 6
------------------------
library | ms
------------------------
DOM 3966
Dojo 1.2.3 22750
plugd-a (Dojo) 24189
Dojo 1.3.0 24249
jQuery 1.3.2 44314
MooTools 1.2.1 69346
jQuery 1.2.6 104407


Internet Explorer 7
------------------------
library | ms
------------------------
DOM 612
Dojo 1.2.3 3641
plugd-a (Dojo) 3748
Dojo 1.3.0 3861
jQuery 1.3.2 5031
MooTools 1.2.1 7658
jQuery 1.2.6 10468


Internet Explorer 8
------------------------
library | ms
------------------------
DOM 499
Dojo 1.3.0 2327
plugd-a (Dojo) 2455
Dojo 1.2.3 2922
jQuery 1.3.2 3170
MooTools 1.2.1 5876
jQuery 1.2.6 7049



The essential library


var $ = {
// essential stuff for TaskSpeed test by WebReflection
// Mit Style License
addEventListener:document.addEventListener?
function(name, callback, bool){
this.addEventListener(name, callback, bool);
}:
function(name, callback, bool){
this.attachEvent("on" + name, callback);
}
,
getSimple:function(selector){
for(var
split = selector.split("."),
result = [],
re = new RegExp("\\b" + split[1] + "\\b"),
list = this.getElementsByTagName(split[0] || "*"),
length = list.length,
i = 0,
j = 0,
node;
i < length; ++i
){
node = list[i];
if(re.test(node.className))
result[j++] = node;
};
return result;
},
indexOf:Array.prototype.indexOf || function(value, i){
for(var
length = this.length,
i = i < 0 ? i + length < 0 ? 0 : i + length : i || 0;
i < length && this[i] !== value;
++i
);
return length <= i ? -1 : i;
},
removeEventListener:document.removeEventListener?
function(name, callback, bool){
this.removeEventListener(name, callback, bool);
}:
function(name, callback, bool){
this.detachEvent("on" + name, callback);
}
,
slice:Array.prototype.slice
};


The test suite

// TaskSpeed, the DOM way by WebReflection
window.tests = {

"make": function(){
for(var
body = document.body,
ul = document.createElement("ul"),
li = document.createElement("li"),
i = 0,
fromcode;
i < 250; ++i
){
fromcode = ul.cloneNode(true);
fromcode.id = "setid" + i;
fromcode.className = "fromcode";
fromcode.appendChild(li.cloneNode(true)).appendChild(document.createTextNode("one"));
fromcode.appendChild(li.cloneNode(true)).appendChild(document.createTextNode("two"));
fromcode.appendChild(li.cloneNode(true)).appendChild(document.createTextNode("three"));
body.appendChild(fromcode);
};
return $.getSimple.call(body, "ul.fromcode").length;
},

"indexof" : function(){
for(var body = document.body, index = -1, i = 0; i < 20; ++i)
index = $.indexOf.call(body.getElementsByTagName("ul"), document.getElementById("setid150"));
return index;
},

"bind" : function(){
for(var callback = function(){}, li = document.body.getElementsByTagName("li"), length = li.length, i = 0, total = 0, node; i < length; ++i){
node = li[i];
if(node.parentNode.nodeName == "UL"){
++total;
$.addEventListener.call(node, "click", callback, false);
};
};
return total;
},

"attr" : function(){
for(var result = [], ul = document.body.getElementsByTagName("ul"), length = ul.length, i = 0; i < length; ++i)
result[i] = ul[i].id;
return result.length;
},

"bindattr" : function(){
for(var callback = function(){}, li = document.body.getElementsByTagName("li"), length = li.length, i = 0, total = 0, node; i < length; ++i){
node = li[i];
if(node.parentNode.nodeName == "UL"){
++total;
$.addEventListener.call(node, "mouseover", callback, false);
node.setAttribute("rel", "touched");
$.removeEventListener.call(node, "mouseover", callback, false);
};
};
return total;
},

"table": function(){
for(var
body = document.body,
table = document.createElement("table").appendChild(document.createElement("tbody")).parentNode,
tr = document.createElement("tr"),
td = document.createElement("td"),
length = 40,
i = 0,
madetable,
cell;
i < length; ++i
){
madetable = table.cloneNode(true);
madetable.className = "madetable";
cell = body.appendChild(madetable).firstChild.appendChild(tr.cloneNode(true)).appendChild(td.cloneNode(true));
cell.appendChild(document.createTextNode("first"));
cell.parentNode.insertBefore(td.cloneNode(true), cell);
};
tr = body.getElementsByTagName("tr");
length = tr.length;
i = 0;
for(var total = 0; i < length; ++i)
total += tr[i].getElementsByTagName("td").length;
return total;
},

"addanchor" : function(){
var a = document.createElement("a");
a.setAttribute("href", "http://example.com");
a.appendChild(document.createTextNode("link"));
for(var ul = $.getSimple.call(document.body, "ul.fromcode"), length = ul.length, i = 0, total = 0, childNodes, j, len, node; i < length; ++i){
childNodes = ul[i].childNodes;
j = 0;
len = childNodes.length;
while(j < len){
node = childNodes[j];
if(node.nodeName === "LI"){
++total;
node.appendChild(a.cloneNode(true));
};
++j;
};
};
return total;
},

"append": function(){
for(var div = document.createElement("div"), body = document.body, i = 0, node; i < 500; ++i){
node = div.cloneNode(true);
node.setAttribute("rel", "foo2");
body.appendChild(node);
};
for(var div = body.getElementsByTagName("div"), length = div.length, i = 0, total = 0; i < length; ++i)
total += div[i].getAttribute("rel") === "foo2";
return total;
},

"addclass-odd" : function(){
for(var div = document.body.getElementsByTagName("div"), length = div.length, i = 0, total = 0; i < length; ++i)
total += i % 2 ? !!(div[i].className += " added odd") : !(div[i].className += " added");
return total;
},

"style" : function(){
for(var div = $.getSimple.call(document.body, "div.added"), length = div.length, i = 0, style; i < length; ++i){
style = div[i].style;
style.backgroundColor = "#ededed";
style.color = "#fff";
};
return length;
},

"removeclass" : function(){
for(var re = /\s*\badded\b/g, div = $.getSimple.call(document.body, "div.added"), length = div.length, i = 0, node; i < length; ++i){
node = div[i];
node.className = node.className.replace(re, "");
};
return length;
},

"sethtml": function(){
for(var div = document.body.getElementsByTagName("div"), length = div.length, i = 0; i < length; ++i)
div.innerHTML = "<p>new content</p>";
return div.length;
},

"insertbefore" : function(){
for(var p = document.createElement("p"), ul = $.getSimple.call(document.body, "ul.fromcode"), length = ul.length, i = 0, total = 0; i < length; ++i){
for(var a = ul[i].getElementsByTagName("a"), len = a.length, j = 0, node; j < len; ++j){
++total;
node = a[j];
node.parentNode.insertBefore(p.cloneNode(true).appendChild(document.createTextNode("A Link")).parentNode, node);
};
};
return total;
},

"insertafter" : function(){
for(var p = document.createElement("p"), ul = $.getSimple.call(document.body, "ul.fromcode"), length = ul.length, i = 0, total = 0; i < length; ++i){
for(var a = ul[i].getElementsByTagName("a"), len = a.length, j = 0, node; j < len; ++j){
++total;
node = a[j];
node.parentNode.appendChild(p.cloneNode(true).appendChild(document.createTextNode("After Link")).parentNode);
};
};
return total;
},

"destroy": function(){
var result = $.getSimple.call(document.body, "ul.fromcode"),
length = result.length,
i = 0,
node;
while(i < length){
node = result[i++];
node.parentNode.removeChild(node);
};
return length;
},

"finale": function(){
var body = document.body;
while(body.firstChild)
body.removeChild(body.firstChild);
return body.getElementsByTagName("*").length;
}

};


Conclusion

I do not want to spend a word about these results, but I guess we have to think about them.

Thursday, March 26, 2009

[PHP] Strict error on static call? Solved!

Just a quick post about Strict standard error when we have a class method which would like to behave differently if called statically.
Apparently, and this is a truly old bogus I opened ages ago, the solution was to supress Strict errors (lol, thanks developers) even if in every other programming language, via overload, this kind of situation could be solved in a bit.

How to solve the problem?

While last post I suggested a couple of runtime solutions, this time I suggest to simply avoid the method definition and use a different one with a meaningful name. In this example I created a String class:

class String {

// choose a recognizable name for protected method
static protected function _concat(array $arguments){
return new self(implode('', $arguments));
}

// use magic __callStatic function
static public function __callStatic($name, array $arguments){
// check the recognizable name
switch($name = '_'.$name){
case '_concat':
// return its call
return self::$name($arguments);
}
}

protected $__value__; // save the string somewhere

// assign initial string, if any
public function __construct($__value__ = ''){
$this->__value__ = $__value__;
}

// use magic __call method
public function __call($name, array $arguments){
// check the recognizable name
switch($name = '_'.$name){
case '_concat':
// normalize expected arguments
array_unshift($arguments, $this->__value__);
// return its call
return self::$name($arguments);
}
}

// this is a String class ...
public function __toString(){
return $this->__value__;
}

}


// test the alchemy
$str = new String('Hello');
var_dump(
String::concat('Hello', ' ', 'World', '!') == $str->concat(' ', 'World', '!')
// true, both are Hello World!
);

As we can see, errors are gone and the code is much easier to maintain. Hope this will help (performances? ... oh, come on!)

[js.php] A JavaScript Object Like PHP Class

PHP 5.3 introduces the Closure class which is really useful and more powerful than good old lambdas via create_function.
These are main limits of Closure class:

  • you cannot serialize a Closure instance (and json_encode does not solve the problem at all)

  • you cannot inject scopes via $this unless the closure comes from a class method


While with an emulated prototype style class, something I tried months ago as well, the first point could not be a problem, to solve the second one is quite inevitable to use a Python like variable as first argument, called $self, to make the Closure both portable and re-adaptable.


JSObject :: JavaScript Object Like PHP Class


/** js.php basic JSObject implementation
* @author Andrea Giammarchi
* @blog WebReflection.blogspot.com
* @license Mit Style License
*/
class JSObject implements ArrayAccess {

// public static prototype
static public $prototype;

// ArrayAccess Interface
public function offsetExists($index){return isSet($this->$index);}
public function offsetGet($index){return $this->$index;}
public function offsetSet($index, $value){$this->$index = $value;}
public function offsetUnset($index){unset($this->$index);}

// Invoked lambdas via $this or self::$prototype
public function __call($index, array $arguments){

// inject $this as first argument
array_unshift($arguments, $this);

// invoke the callback
return call_user_func_array(

// if it has been assigned to the object itself
isset($this->$index) ?

// it has priority
$this->$index :

// otherwise invoke from self::$prototype
self::$prototype->$index
,
$arguments
);
}

// JS like behavior, ready for extends
public function __toString(){
return '[object '.get_class($this).']';
// e.g. [object JSObject]
}

// Relevant Global Object implementations
public function getPrototypeOf(){
return get_class($this);
}
public function hasOwnProperty($index){
return isset($this->$index);
}
public function isPrototypeOf(/* string */ $class){
return $this instanceof $class;
}
public function toSource(){
// we could implement __sleep and __wakeup
// to avoid closure serialization (not possible yet)
return serialize($this);
}
public function toString(){
return $this->__toString();
}


// not standard method, anyway useful
public function toJSONString(){
// we could parse properties in a foreach
// to filter meaningless closures, if any
return json_encode($this);
}
}

// the global prototype is a JSObject too
JSObject::$prototype = new JSObject;

// JSObject factory: e.g. $myobj = JSObject(); // rather than new JSObject;
function JSObject(){
return new JSObject();
}

Above class uses an interface from the great SPL, an in-core extension present since PHP 5.1
The rest is theoretically compatible with old style lambdas, static functions, or new Closure instances. Here we go with some example:

// we can assigns prototypes everywhere ...
JSObject::$prototype->getName = function($self){
return $self->name;
};

$o = JSObject();

// ... even after JSObject instances creation
JSObject::$prototype->writeAge = function($self){
echo $self->getName().' is '.$self->age.' years old.';
};

// assign properties
$o->name = 'Andrea';
$o->age = 30;

// test some JS method
echo $o->toJSONString();
// {"name":"Andrea","age":30}

echo $o;
// [object JSObject]

echo $o->toSource();
// O:8:"JSObject":2:{s:4:"name";s:6:"Andrea";s:3:"age";i:30;}

// or tests runtime methods
$o->writeAge();
// Andrea is 30 years old.

// we can assign a custom method runtime
$o->getSurname = function($self){
return 'Giammarchi';
};

// custom methods have priority over prototype
$o->getName = function($self){
return $self->name.' '.$self->getSurname();
};

$o->writeAge();
// Andrea Giammarchi is 30 years old.

Is it cool? And more is coming for backward compatibility:

// prototype via function name resolution
JSObject::$prototype->getName = 'JSObject_getName';

// the function with a prefix to avoid conflicts
function JSObject_getName($self){
return $self->name;
}

// a simple test case
$o = JSObject();
$o->name = 'Andrea';

echo $o->getName();
// Andrea

And obviously we can do the same with create_function:

// prototype via lambda
JSObject::$prototype->getName = create_function('$self','
return $self->name;
');


Conclusion


Via SPL, closures, and some convenient trick, we could completely change the code style of PHP. Performances are always a priority, in any case, but with a couple of good practices, some discarded or "language useless" piece of ECMAScript, we could use JS style as low level structure for more Object Oriented frameworks or completely different ways to code.

What's next?


It is ages that I am waiting for a stable PHP 5.3 plus PECL extensions (in particular the php_operator to add operator overloads) to be able to create a JavaScript version of PHP. I have already created similar classes and my vision is a one2one JavaScript style framework created entirely via PHP. Craziness? Non-sense? Dunno, just try to imagine a Jaxer like behavior in every host with "just" PHP support ... is it a cool idea? Well, please contact me if you are interested ;)

Monday, March 23, 2009

[IE8] Global constants via defineProperty ... Illusion!

I do not want to spend a single word about Internet Explorer 8 Object.defineProperty implementation, which works only with DOM prototypes and the super global window but not with user defined objects, as __defineGetter__ and __defineSetter__ do since ages:
Standards are an important factor to ensure browser interoperability for the Web developer (n.d. oh, really?!??!?!!!!). The accessor property syntax has only recently begun standardization (you guys have a weird concept of the time ... or the meaning of "recent" in IT therms ...). As such, many browsers support an older, legacy syntax ... (n.d. which at least has dignity to work with every kind of object ... )


Anyway, few things are better than nothing, so welcome to Object.defineProperty!

Let IE8 behaves like every other or change every other to respect new M$ standard?

This was the first question when I thought about this new global function: does it mean we finally have a way to emulate __defineGetter__ and setter in Internet Explorer as well? First of all: NO, since IE implementation works only with DOM and window, secondly, we need to add an Object.prototype method (to be honest ... two) and we all know that Object.prototype is the "untouched one".
So, let's do in the other way, we can add a method to the global function Object, which is less obtrusive and more compatible ^_^;;

if(!Object.defineProperty && Object.prototype.__defineGetter__)
// a silly WebReflection idea
Object.defineProperty = function(obj, prop, getset){
if(getset.get)
obj.__defineGetter__(prop, getset.get);
if(getset.set)
obj.__defineSetter__(prop, getset.set);
};

Well done, now we should simply parse every passed obj to understand if those are IE8 compatible ... is it worthy? ... dunno yet, just for fun, destroy IE8 environment with this evil Object.prototype if you want:

if(!Object.prototype.__defineGetter__ && Object.defineProperty){
// the second silly WebReflection idea!
Object.prototype.__defineGetter__ = function(prop, get){
Object.defineProperty(this, prop, {get:get});
};
Object.prototype.__defineSetter__ = function(prop, set){
Object.defineProperty(this, prop, {set:set});
};
};

Same problem, we cannot use a method with every browser ... the only good part of this global Object method is described in this msdn page, an addEventListener, finally, for IE8 too and every node without usage of wrappers (usually the $ object ...)


The insane idea: Global Constants for EveryBody?

... oooOOOOOOOO Crap! Even if we can do something like this:

// create the evil plan!
Object.defineProperty(
window,
"nobodyCanChangeMe",
{
get:function(){
return "I am like a constant!";
},
set:function(){
throw new Error(
"You cannot change a constant, don't ya know it?"
);
}
}
);

// test the evil plan! (muHaHAHAHA in the background ...)
nobodyCanChangeMe = 123;
// Error: You cannot change a constant, don't ya know it?

You will probably be (un)surprised to know that Internet Explorer 8 (tada, tada, taDAAA!!!) completely ignore the setter whenever you decide to redefine the property!!!

// above perfect evil plan code ... plu ...

Object.defineProperty(window, "nobodyCanChangeMe", {get:function(){
return "you must be joke!";
}});
alert(nobodyCanChangeMe); // you must be joke!


As Summary

VBScript via browser supports constants since dunno how many years. I personally wrote a PHP define like functions ages ago but nothing, Microsoft decided to release IE8 without constants, which are supported almost by evey other (FireFox, Chrome, Safari, Opera -- buggy/meaningless in the latter case) so there is no way to protect our code for JsonP requestes, safe evaluations, whatever you would like to be "99%" sure nobody can change, etc etc ... so this is a thank to IE Team, they worked hard, but this is also a: was it that difficult to put more effort in the JavaScript engine, rather than scam the world with those useless page loading benchmarks?

Enjoy the new Web 2.IE8 Era!

Friday, March 20, 2009

noSWFUpload - Zero Plug-In Multiple Upload

As announced a couple of days ago, I am finally proud to introduce my last library free Multiple Upload Component, now compatible with every browser and always without usage of 3rd parts plug-ins.


This little project has been hosted in Google Code and I promise I'll write there a complete documentation asap. Righ now, you can read the project source code via zip to understand what he little API is doing.

Update I added a couple of sections in the Wiki page ;)

Compatibility?
  • Internet Explorer 5.5 (probably 5 too), 6, 7, and 8
  • FireFox? 3 or greater
  • Google Chrome 1.0
  • Opera 8, 9, and 10
  • Safari 4 (current beta)
  • other browsers via unobtrusive iframe


Try the demo if you do not believe it :P

Monday, March 16, 2009

packed.it ... bye bye my darlin'

I spent a month about two years ago to create packed.it, which has been used by few developers, which cannot compete with other known application even if it is absolutely unique.
Well, the domain is expiring, the site is hosted thanks to a friend of mine, the MyMin project in Python, PHP, C#, JavaScript, will be probably moved in Google Code if and when I will have time.

Right now it is not even working with FireFox, just IE7 and few other browsers ... the reason? No time to update it, and low interests from Web community.

So what's next? I have no idea, but if you are interested, packed.it domain is gonna be free soon, and my service is gonna be down soon as well.

Thanks to those developers who believed in packed.it and used it for some project :)

Sunday, March 15, 2009

Multiple Upload With Progress: Every Browser No Flash !!!

Update: released official version in Google Code, cross browser, and easy to use. blog enry


Ok guys, this is a quick and dirty entry in my blog. I need to write documentation, create the project in Google Code, explain better what I have done and how it works.
I do not want to give you the zip right now because I have to change name (silly me do not check before) and to do last tests ... but basically, what I have created this week end, is a graceful enhanced multiple file upload manager compatible with Chrome, FireFox, Internet Explorer (5.5 or greater), Opera, Safari.



The manager wrap an input type file and manages it allowing multiple files selection, where supported, or one after one insert with possibility to remove one or more file from the list.

Everything is absolutely customizable, since the wrapper is entirely in CSS, the library has a language namespace for errors or messages, and events are created by developers.

In those browsers were Ajax upload is not supported, the progress bar is simulated, but there is the feeling that something is happening.

In FireFox, where Ajax upload is supported, the progress is still simulated but at least the size, sent or total, is real.

Stay tuned for the official announcement, enjoy the demo in my website.

Quick thanks and credit to Silk Icon Set from famfamfam!

P.S. Yes, there is a file type filter as well, Flash like, and I have solved server side $_FILES problem with Safari 4 ... but please wait next blog entry!

Monday, March 09, 2009

Safari 4 Multiple Upload With Progress Bar

Update - I slightly modified the demo page adding another bar, the one for the current file. I'll update the zip asap but all you need is a copy and paste of the JS in the index. Apparently multiple should be set as multiple, rather than true ... in any ... it works as long as it is an attribute.


This one from Ajaxian has been one of the best news I could read about HTML5 specs and browsers evolution.
I could not wait to download Safari 4 and test instantly this feature.
I have always been interested in this possibility, both progress bar, plus multiple uploads and that's why I would like to add this post to this list:


First Step: The Input Type File

We can create a multiple input files in different ways: directly in the layout

<input type="file" multiple="multiple" />

or via JavaScript:

var input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("multiple", "multiple"); // note: input.multiple = "multiple" does not work in Safari 4 beta

I know we all like graceful degradation, but in this post I will only talk about a client side progress bar, something that is cool and possible, so far, only via JavaScript ;-)


Second Step: XMLHttpRequest Version 2

The last implementation of this constructor brings some cool stuff with him, the XMLHttpRequestUpload interface, used by an automatic created property called upload.
The reason this property is as cool as welcome, is that it can trace sent binary data via dispatched events like onload, onprogress, and others.

var xhr = new XMLHttpRequest,
upload = xhr.upload;
upload.onload = function(){
console.log("Data fully sent");
};
xhr.open("post", page, true);
xhr.send(binaryData);

Above snippet is the basis of the new feature introduced by Safari 4, feature better explained in the dedicated example I prepared for this post.


Third Step: The PHP Manager

If we use multiple attribute without XMLHttpRequest, we simply need to set a name, and manage data in the server via the superglobal $_FILES. But if we want to send directly the binary stream, the only thing we need to do in the server, security checks a part, is to save the content sent via input:

<?php
// e.g. url:"page.php?upload=true" as handler property
if(isset($_GET['upload']) && $_GET['upload'] === 'true'){
$headers = getallheaders();
if(
// basic checks
isset(
$headers['Content-Type'],
$headers['Content-Length'],
$headers['X-File-Size'],
$headers['X-File-Name']
) &&
$headers['Content-Type'] === 'multipart/form-data' &&
$headers['Content-Length'] === $headers['X-File-Size']
){
// create the object and assign property
$file = new stdClass;
$file->name = basename($headers['X-File-Name']);
$file->size = $headers['X-File-Size'];
$file->content = file_get_contents("php://input");

// if everything is ok, save the file somewhere
if(file_put_contents('files/'.$file->name, $file->content))
exit('OK');
}

// if there is an error this will be the output instead of "OK"
exit('Error');
}
?>



Last Step: The Client Manager With The Progress Bar

This is the last thing we should care about, and only after we are sure we implemented best security checks to avoid problems for users and the server itself. In this example I did not implement too many checks, so please take it as a hint, rather than a final solution for public production environments.
The client side is really simple and entirely managed via JavaScript.

/** basic Safari 4 multiple upload example
* @author Andrea Giammarchi
* @blog WebReflection [webreflection.blogspot.com]
*/
onload = function(){

function size(bytes){ // simple function to show a friendly size
var i = 0;
while(1023 < bytes){
bytes /= 1024;
++i;
};
return i ? bytes.toFixed(2) + ["", " Kb", " Mb", " Gb", " Tb"][i] : bytes + " bytes";
};

// create elements
var input = document.body.appendChild(document.createElement("input")),
bar = document.body.appendChild(document.createElement("div")).appendChild(document.createElement("span")),
div = document.body.appendChild(document.createElement("div"));

// set input type as file
input.setAttribute("type", "file");

// enable multiple selection (note: it does not work with direct input.multiple = true assignment)
input.setAttribute("multiple", "multiple");

// auto upload on files change
input.addEventListener("change", function(){

// disable the input
input.setAttribute("disabled", "true");

sendMultipleFiles({

// list of files to upload
files:input.files,

// clear the container
onloadstart:function(){
div.innerHTML = "Init upload ... ";
bar.style.width = "0px";
},

// do something during upload ...
onprogress:function(rpe){
div.innerHTML = [
"Uploading: " + this.file.fileName,
"Sent: " + size(rpe.loaded) + " of " + size(rpe.total),
"Total Sent: " + size(this.sent + rpe.loaded) + " of " + size(this.total)
].join("<br />");
bar.style.width = (((this.sent + rpe.loaded) * 200 / this.total) >> 0) + "px";
},

// fired when last file has been uploaded
onload:function(rpe, xhr){
div.innerHTML += ["",
"Server Response: " + xhr.responseText
].join("<br />");
bar.style.width = "200px";

// enable the input again
input.removeAttribute("disabled");
},

// if something is wrong ... (from native instance or because of size)
onerror:function(){
div.innerHTML = "The file " + this.file.fileName + " is too big [" + size(this.file.fileSize) + "]";

// enable the input again
input.removeAttribute("disabled");
}
});
}, false);

bar.parentNode.id = "progress";

};

The external file with sendFile and sendMultipleFile function is in my repository and in the attached zip, while a workable example page with a limit of 1Mb for each file is here in my host.

Sunday, March 01, 2009

PHP to Jaxer Server And Vice-Versa

Basis

If we have a configuration Jaxer + PHP, as is as example in my pampa-j project, we should know that these two languages cannot directly interact as is, for example, with Jaxer and Java.
The interpreted and executed order is this one:

  1. the PHP module parses the request and the page before Jaxer module

  2. after PHP has finished its stuff, the Jaxer Server module parses the page which could has been modified during PHP execution

  3. after the Jaxer Server has finished its stuff, the user receives the generated page

Above order means that we can pass variables to Jaxer but we cannot pass back results to PHP

<?php // simple variable from PHP to Jaxer
$myVar = 'Hello World';
echo '<script runat="server">
myPHPVar = '.json_encode($myVar).';
onload = function(){
// will show Hello World
document.body.innerHTML = myPHPVar;
};
</script>';
?>

As summary, if we print out a script tag wth a valid JavaScript for server, client, or both, Jaxer Server will consider that tag as part of the page to execute.


The Other Way Round?


Since Jaxer Server parses tha page after PHP has finished, and since PHP will not be connecte to the Jaxer Module and will simply close its thread, during Jaxer page generation/parsing we cannot use PHP because there is no connector as is for Java.
At this point we could create a workaround using one of these strategies and considering that all we gonna do will be on the server, before the client will receive the page:

  • create a socket via PHP and connect to it via Jaxer during its page parsing

  • call somehow PHP runtime during Jaxer Execution


While the first point requires skills and the possibility to change server configuration, the second option could be implemented via Synchronous Ajax call from Server to Server.


Sounds Insane, but it is working!

These is a simple test case I created to show you how it is possible to communicate PHP to Jaxer (creating a specific object) and vice-versa, calling PHP functions runtime via Jaxer.
The final concept is showed in next snippet:

<?php
// require the Jaxer.php file to prepare
// the Jaxer.PHP object
// Jaxer is interpreted after PHP
require 'Jaxer.php';
?>
<script runat="server">
// a simple test case, monitor the tme
var t = new Date;
onload = function(){

// retrieve the length of a string
var len = Jaxer.PHP.call("strlen", "test"), // 4
myFuncResult;
try {

// change runtime the page to call
Jaxer.PHP.url = 'myFunc.php';

// call a function defined in that page
myFuncResult = Jaxer.PHP.call("myFunc"); // "Hello Jaxer Server"

// call something undefined to test errors
myFuncResult = Jaxer.PHP.call("noFunc"); // shows an error on the catch
} catch(e) {

// show the error
document.body.appendChild(document.createTextNode(e.message)); // error from PHP, if any
document.body.appendChild(document.createElement("br"));
};

// take the elapsed time
t = (new Date - t) / 1000;

// show some information
document.body.appendChild(document.createTextNode(len + " - " + myFuncResult));
document.body.appendChild(document.createElement("hr"));
document.body.appendChild(document.createTextNode("Executed in " + t + " seconds"));
};
</script>

To make above code possible, all we need are a couple of files, the Jaxer.php interpreter:

<?php
/** Runtime Jaxer to PHP
* (C) Andrea Giammarchi
* Mit Style License
*/

// @string your secret password, it will NOT be showed in the client
$JaxerSecret = sha1('my secret pass');

// if Jaxer Server sent a request with a valid secret and a function to call ...
if(isset($_POST['JaxerSecret'], $_POST['Jaxer']) && $_POST['JaxerSecret'] === $JaxerSecret){

/** Error manager
* @param int error level
* @param string file that generated the error
* @param int line that generated the error
* @param mixed the context (optional, not used)
*/
function JaxerError($level, $message, $file = null, $line = null, $context = null){
echo ":".json_encode(array('level' => $level, 'message' => $message, 'file' => $file, 'line' => $line));
exit(0);
}

/** Exception manager
* @param Exception the generic generated Exception
*/
function JaxerException(Exception $e){
JaxerError($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine());
}

// error manager configuration
@set_error_handler('JaxerError');
@set_exception_handler('JaxerException');

// Jaxer variable is a serialized object with two properties
// - the name of the function to call
// - one or more arguments to send to use with called function
$js = json_decode($_POST['Jaxer']);

// the Jaxer to PHP result is always a JSON serialized result
echo json_encode(call_user_func_array($js->name, $js->arguments));
} else

// Jaxer needs to know the secret
// and to use the Jaxer.PHP
// this is created runtime via PHP
echo '<script runat="server">'.
str_replace(
'{JaxerSecret}',
$JaxerSecret,
file_get_contents('Jaxer.php.js') // read the file
).
'</script>';
?>

the Jaxer.php.js file with the JavaScript runtime created object:

/** Runtime Jaxer to PHP
* (C) Andrea Giammarchi
* Mit Style License
*/
Jaxer.PHP = {

// the url with Jaxer.php file
url:"Jaxer.php",

// the PHP.call function
// Accepts the name of the PHP function to call
// plus zero, one, or more arguments to send
call:function(slice){
var send = {
async:false,
method:"POST",
onsuccess:function(response){
if(response.charAt(0)===":"){
var result = JSON.parse(response.substring(1)),
e = new Error;
for(var key in result)
e[key] = result[key];
send.result = null;
throw e;
} else
send.result = JSON.parse(response);
}
};
return function(name){
send.url = Jaxer.PHP.url;
Jaxer.XHR.send(
// {JaxerSecret} is replaced via PHP
"JaxerSecret={JaxerSecret}&Jaxer=" + encodeURIComponent(
JSON.stringify({name:name, arguments:slice.call(arguments, 1)}
)), send);
return send.result;
}
}(Array.prototype.slice)
}

... and finally, a generic page with one or more functions defined, in this case the myFunc.php file:

<?php
// require the Jaxer to PHP manager
// if this page is called directly
// the secret will NOT be whoed
// while if this page is called
// via Jaxer.PHP, the manager
// will simply execute the required code
require 'Jaxer.php';
function myFunc(){
return 'Hello Jaxer Server';
}
?>

The secret is a truly simple security system to avoid direct php page calls and since it is interpreted only on the server, the client will never know this secret (unless our server is not exposing source codes, in this case the secret should be already hashed via sha1 in the source).


Pros And Cons

This strategy could sound cool but it is not the ideal way to interact between these two different modules. The Jaxer to Java way is much better but at least here we have the possibility to send back something or to do via PHP something impossible to do via Jaxer. The fact I put a timer to monitor the delay means you should pay attention because this way is extremely slow. The ideal case scenario is, when absolutely necessary, call PHP only once, creating a clever function able to receive one or more arguments, delegates tasks in the current PHP code, and send back a single object with one or more results. In few words, if you are able to perform one single call to send and receive everything you need, this solution could be fine. In every other case, this solution could require an insane stress for the server and for a single page to show.

In any case, have fun :)

P.S. Here I am with a zip file to test directly this post code

Saturday, February 28, 2009

On JavaScript Inheritance Performance - One Step Back

Few days ago I wrote a post about this argument, proposing an alternative "best option" way to use an injected parent in each method.

As soon as more developers read my post, more sparkles came out from the fire: true classical inheritance simulation via missed methods in the chain, exception during methods execution that could trap the temporary injected parent, and other interesting stuff again.

At the end of all these tests, benchmark, and libraries evaluation, I decided to step backward about my proposal, making things simple, logic, and extremely fast (as much as possible).

My Conclusions


  1. if we inject a parent, we have to change and/or wrap the original method, adding noise in the execution and inevitably more operations to perform (read: less performances)

  2. for each inherited metod, even if it is the same of the parent one, we need to add functions and code which means more RAM and less portability

  3. more we over-mess the simple JavaScript inheritance stack, less control we'll have for debugging and maintenance

  4. using strategies like the one adopted from the YUI library could only add confusion because if we put the instance in a parent method, the super one or the super.super.super (and go on), its parent will be still the original one and if we call this.superclass in the wrong context, results will be always unpredictable for that method (unless we did not write down every specific case, if the instanceof A called that method ... if the instanceof B called that method, etc etc)


Accordingly, the fact we are all lazy developers should not mean we can loose performances, use more RAM, make things more complicated than we need, specially in this Web era where devices with limitations could use our code without problems (iPhone) but only if performances are reasonable and downloaded code size is, again, reasonable.


The new best option to use a parent method

Following the test proposed in the old post, this is how I can obtain best performances even against classical way to use parent methods:

function WRSub(name, age){
// classical and debug prone parent call (fastest)
WRClass.call(this, name);
this.age = age;
};
wr.extend(WRSub, WRClass, {
// WebReflection parent method call in closure
// faster than runtime method resolution:
// WRClass.prototype.toString.call(this)
toString:(function(toString){
return function(){
return toString.call(this) + ": " + this.age;
}
})(WRClass.prototype.toString)
});



Summary

I love performances, readable code (big lol from kangax? :P), code portability, logic execution, and all we need is already there in the language.
We do not need to over mess the inheritance chain, the only thing we need is a god way to extend able to understand if the browser is missing hidden methods (toString, etc) and nothing else.
Once we have this good way to extend a constructor, everything else will be fast, readable, debug prone, and compatible with every possible situation, without breaking our neck to understand why that method in that case behaved differently, or that parent did not change as expected, etc etc ... robust, reliable, and fast code? Forget all these parent/$super/superclass implementations, put what you need in a closure to simplify and speed up the code and that's it, as my new benchmark shows where my clean and simple implementation bites every other library, even the classical full namespace way.


News about WebReflection Library

I have added a couple of things which are truly common on daily basis development. You can find a list of all JS 1.6 Array methods to use with whatever list you want, DOM Collections included.

wr.Array.forEach.call(document.getElementsByTagName("div"), function(div, i, collection){
div.innerHTML = "I am div " + (i + 1);
});

Those are compatible with ECMAScript specs, native performances for updated browsers, best performances for IE and others.
The wr.Object.forIn is the classical for in loop plus hidden methods in IE, something we can use to extend constructors or to inspect objects.
I am considering to put the hasOwnProperty check by default to loop only properties assigned, and not those inherited, but for extending purpose, we need to loop everything.
setInterval and setTimeout are natives or wrapped to support extra arguments as well.
wr.id is the classic method to generate an expando or a unique id for each call while wr.is is a function with all native checks via Object.prototype.toString.

The purpose of the library is not (yet) to substitute other libraries, it is just about basic things we always need, focused on performances, compatibility, etc.
I'll add more, but so far enjoy the extend, now free of bugs since different, the forIn, the is, the id, and current Array implementations.

Tuesday, February 24, 2009

[OT] ... if Gmail is down I can't ... (aka: new era paranoia)


  1. receive emails from my PC or my Android

  2. send emails from my PC or my Android

  3. follow developers via mailing list via PC or Android

  4. chat via GTalk with buddies (mainly developers)


Bloody Hell I feel outside the world!!!

P.S. ... but fortunately in few minutes everything went back :D

Saturday, February 21, 2009

Yahtzee! On Line to print or simply play

You know ... sometimes in 2009 a dice based game could be an evening resolution or simply nice time to spend with somebody else.
I was out of paper and after the second try to draw manually the Yahtzee table I though: Why on earth I do not create a table to play with?

Here I am: Yahtzee! on line
You can print in landscape and reuse the paper 4 times (two tables in the front, two in the back) or to be even more green, you can simply put your green laptop in the corner of the table and play with the interactive table.
I usually play with F11 option (full screen browser), but I am not sure the automatic score is a good idea (more interesting to count manually who is winning, isn't it?)

Have fun :)