My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label firefox. Show all posts
Showing posts with label firefox. Show all posts

Tuesday, November 17, 2009

195 Chars To Help Lazy Loading

Update
removed named function expression

Update
I wrote events letters in the wrong place, please use the latest script

We have talked many times about performances, and not only here.
One common technique to speed up a generic online page is the lazy loading.
For lazy loading I mean:
  • runtime dependencies resolution via script injection, preferably including all dependencies we need in a shot rather than script after script
  • Google comments style, where code is evaluated when required but the size is still there
  • namespaced strings, an example I have explained via code in Ajaxian
  • whatever else, because sometimes we need this or that library only in certain conditions


What Is The Problem

If we would like to widely adopt this lazy load pattern, we should be aware about a "little detail": Firefox < 3.6 does not support document.readyState, an historically valid Internet Explorer feature adopted in HTML5 and present in basically every other browsers.
We can find the readyState description and the related bug in Mozilla domain.
Reading suggestions, I found quite pointless the long diatribe about:

Should it be "loading" or "interactive" before it will switch to "complete" ?

IMHO, who cares, as long as we can rely in the final statement: complete

Affected Libraries

I have no idea but for sure jQuery! The event.js file shows at line 857 this check for the bindReady event:

// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
return jQuery.ready();
}

The code goes on with common DOMContentLoaded checks and emulations.
The problem is that with such library where basically everything starts with an ready event:

$(function(){
// the ready event we are theoretically
// sure will be fired even if the
// code has been loaded after
});

every Firefox < 3.6 user will miss that code, plug-in, extension, whatever.
I have already informed jQuery dev ML about this problem but obviously they already know. John Resig told me that there is no guarantee the ready event will be fired if the page has been loaded.
Fair enough, I can perfectly understand John point which is: all jQuery supported browsers may not support document.readyState.
AFAIK, even if this is a good reason to avoid some obtrusive code, we all would expect consistency from a framework so if something worked even in IE I can't even think about Firefox problems.

The Solution


This missed FF feature could affect different libraries, not only jQuery.
We, as developers, could help every library author adding 195 uncompressed bytes, even less once deflated, as first stand alone piece of code ever in our page:

// WebReflection Solution
(function(h,a,c,k){if(h[a]==null&&h[c]){h[a]="loading";h[c](k,c=function(){h[a]="complete";h.removeEventListener(k,c,!1)},!1)}})(document,"readyState","addEventListener","DOMContentLoaded");

// NOTE: IE will never consider false s[o]==null

Since Firefox is usually updated automatically, all we need to do once we are sure people are surfing with version 3.6 or greater is simply remove above little line of code.

Explained Solution


// verify that document.readyState is undefined
// verify that document.addEventListener is there
// these two conditions are basically telling us
// we are using Firefox < 3.6
if(document.readyState == null && document.addEventListener){
// on DOMContentLoaded event, supported since ages
document.addEventListener("DOMContentLoaded", function DOMContentLoaded(){
// remove the listener itself
document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
// assign readyState as complete
document.readyState = "complete";
}, false);
// set readyState = loading or interactive
// it does not really matter for this purpose
document.readyState = "loading";
}


Conclusion

Being this a browser problem and not directly libraries related, it does not probably make sense to put this fix just for few months until next FF release. At the same time we can guarantee for Firefox users, and only if the library does not sniff the browser via this read only property, that lazy loaded stuff a la $(rockNroll) will work into our favorite browser too or we could simply rely and with our code into a readyState "complete" check to decide what to do (this is the real reason I have investigated more this problem, but this is another story coming soon).

Tuesday, May 05, 2009

fireEvent for FireFox, Safari, and others

Just a quick update about vice-versa, I have implemented fireEvent to fire, as the method name says itself, events after attachEvent.

Do you prefer the dispatchEvent way with at least 3 different ways to initialize an event usually fired only to call the callback?
It is this:

a.addEventListener("click", function(evt){
location.href = evt.target.href;
evt.preventDefault();
return false;
}, false);

// powerful uh? now think
// when you used something different
// from defaults ...
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(
"click",
true,
true,
this,
0,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null
);
a.dispatchEvent(evt);

against what I think is often all we need:

a.attachEvent("onclick", function(){
location.href = event.srcElement.href;
return event.returnValue = false;
});
a.fireEvent("onclick");

and that's it :)

Tuesday, April 28, 2009

The Fastest Selector Engine For FireFox 3.0 ?

I am putting some effort to make vice-versa project a good, production ready, alternative against common libraries, and since these days I am working hard with XML, XSL(T), and XPath I decided to try an experiment implementing CSS to XPath translator for FireFox 3.0



With version 3.1 we will have querySelector and querySelectorAll but version 3.0 is still the most used one, FireFox speaking!

The nightly build of vice-versa introduces a new file, mainly used for personal experiments via vice-versa library and the first experiment is an improved document.query for those browsers with document.evaluate support without document.querySelectorAll.
Unfortunately Internet Explorer < 8 does not support XPath queries over (x)HTML but at least for FireFox 3.0 I have obtained best overall performances via SlickSpeed Selector Speed Test comparing latest version of each library such Dojo, DOMAssistant, Sizzle (congrats for the new site!), Sly, and finally vice-versa project.
Here the summary, from faster to slower:

vice-versa 760ms
Dojo 1.3.1 868ms (2 tests failed)
DOMAssistant 880ms (good stuff Robert!)
Sly 890ms
Sizzle 914ms

Now, the good part is that nowadays every selector engine seems to perform truly fast and in whatever browser you like, but the "even better" part is that the experiments file in vice-versa is 1Kb (minified and gzipped) and with just "that Kb" it is possible to use a specific and fast selector engine for FireFox 3.0.

Finally, the experimental CSS to XPath translator cannot support pseudo searches like :hover, :active, or similar, due to the XPath nature, a query language mainly designed for XML where CSS, unless we do not transform it via XSLT, has a complete different meaning from the one used in (x)HTML.

I wonder now who will be able to create better overall performances for FireFox 3.0 ( changing my translator implementation, for example ;) )

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!

Wednesday, December 17, 2008

outerHTML for almost every browser ... if you need it ...

We all have to deal with memory leaks problem and apparently a good way to be sure that an HTMLElement has been removed from its "flow" is the outerHTML assignemnt (thanks Ariel for the suggestion)

element.outerHTML = "";
element = null;

If the element is not a document.body or another body parent node, Internet Explorer will "extract" that element from its context, if any, and if there are no other references for that element the null assignment will, theoretically, complete the opera, hopefully solving memory leaks problem for that node as well ...


To remove ... but to replace too ...


Every library has a "swap" or replace method to quickly change an element, but even if we all know that innerHTML is the fastest way to insert content, few libraries use outerHTML to replace nodes, that as far as I know, should be "that fast" in IE as innerHTML is:

// traditional swap, the DOM way
function swap(oldNode, newNode){
var parentNode = oldNode.parentNode;
parentNode.insertBefore(newNode, oldNode);
parentNode.removeChild(oldNode);
};

// spaghetti swap, the outerHTML way
function swap(oldNode, newNode){
oldNode.outerHTML = newNode.outerHTML;
};



outerHTML ... both get and set



try{
HTMLElement.prototype.__defineGetter__.length;
(function(body, removeChild){
HTMLElement.prototype.__defineGetter__(
"outerHTML",
function(){
var self = body.appendChild(this.cloneNode(true)),
outerHTML = body.innerHTML;
body.removeChild(self);
return outerHTML;
}
);
HTMLElement.prototype.__defineSetter__(
"outerHTML",
function(String){
if(!String)
removeChild(this);
else if(this.parentNode){
body.innerHTML = String;
while(body.firstChild)
this.parentNode.insertBefore(body.firstChild, this);
removeChild(this);
body.innerHTML = "";
};
}
);
})(
document.createElement("body"),
function(HTMLElement){if(HTMLElement.parentNode)HTMLElement.parentNode.removeChild(HTMLElement);}
);
}catch(e){};



Conclusion


pro and cons are the same of innerHTML and the reference is lost as is for Internet Explorer, whenever we decide to use this dirty approach to remove or change elements in the DOM. A last example?

function change(strong){
strong.outerHTML = "not strong anymore";
strong = null;
};
onload = function(){
document.body.innerHTML = "click";
};

Thursday, August 21, 2008

How to crash FireFox 3 with 3 lines of code

Hi there, here I am back from holidays :geek:

Before I'll start to write more interesting stuff, here we have 3 lines of JavaScript that could cause problems to our favourite browser, in this case version 3.0.1

I discovered this problem, already part of the bugs report site, trying to emulate keyboards events using the UIEvents interface instead of KeyboardEvents


var e = document.createEvent("UIEvents");
e.initUIEvent("keypress", true, true, this, 1);
document.documentElement.dispatchEvent(e);


Nice one? See you soon ;)

Wednesday, March 12, 2008

Do You Like Browser Benchmarks? Here I am!

Hi guys,
today we will not talk about my last JavaScript ArrayObject creation :D

Today is the benchmark day, and in this case the test is as simple as explicative ... both Math object and scope are two things we use every day for whatever purpose in this baby Web 2.0 era!

Let me start directly with results (ORDER BY speed ASC):

Firefox 3.0b4
----------------------------------
regular avg time in ms: 9.98
scoped avg time in ms: 3.18
encapsulated avg time in ms: 12.98


Safari 3.0.4 (523.15)
----------------------------------
regular avg time in ms: 13.42
scoped avg time in ms: 6.42
encapsulated avg time in ms: 11.82


Opera 9.24
----------------------------------
regular avg time in ms: 13.82
scoped avg time in ms: 9.6
encapsulated avg time in ms: 17.64


Internet Explorer 8.0.6001.17184
----------------------------------
regular avg time in ms: 16.42
scoped avg time in ms: 6.82
encapsulated avg time in ms: 16.82


Firefox 2.0.0.12
----------------------------------
regular avg time in ms: 26.84
scoped avg time in ms: 42.06
encapsulated avg time in ms: 28.64


What kind of benchmark is it?

This is a double test that includes the usage of scoped shortcuts, and the usage of the object that you cannot absolutely get by without: the global Math one!

To understand better this kind of test, please look at these functions:

function regular(){
for(var i = 0, time = new Date; i < 10000; i++)
Math.round(i / Math.PI);
time = new Date - time;
return time;
};

function scoped(){
for(var round = Math.round, PI = Math.PI, i = 0, time = new Date; i < 10000; i++)
round(i / PI);
time = new Date - time;
return time;
};

function encapsulated(){
with(Math){
for(var i = 0, time = new Date; i < 10000; i++)
round(i / PI);
time = new Date - time;
};
return time;
};


The first one, is the most common in every day libraries / scripts, while the second one and the third one, are used by "a little bit more skilled" developers.

The second one, uses the same concept of my good old friend, the smallest FX library from 2006: bytefx

The scoped schortcut is absolutely the fastest way to use a global objet, constructor, whatever you want.

Just think about nested scopes, this amazing ECMAScript 3rd Edition more close to future than many other new program languages ... ( IMO, and sorry for exaggeration :lol: )

When you write the name of something in your scope, the engine looks obviously in the same scope, than in the external one, going on until the super global object, the window

This behavior is basically what should happen using the with statement as well ... but unfortunately, even if this is basically what's up, performances are clearly against the usage of absolutely comfortable with statement.

At the same time, there is one browser that you are probably using right now, that create a bit of confusion about everything I've just said right now: Firefox 2

With quite twice of time, using scoped shortcuts, this browser (the best I've ever used for years, and the one I'll use for other many years) reverse totally my conviction about how does scope work ... anyway, we are lucky because Mozilla staff is creating good stuff with Firefox 3 ... who cares about Firebird and other old versions? :D

Don't you really trust me and my results?
So do this bench by yourself :geek: