Sunday, November 13, 2011

Noise ?

Hi Folks,

I didn't blog for ages now. Without boring you with the reasons, long story short. I just was buried in work. Office + freelancing is probably not a great idea, so I stopped freelancing for now.

Over the past month, I also was very addicted to a new project of mine. I still am!
Its all about ECMAscript, loosely coupled architecture and "true" modular programming patterns. That project (or rathermore the idea) grew bigger and bigger and finally, I ended up with my own little framework, cooked into a library.

Since I started from the scratch, I gave it an oh-so-cool name. It's called "BarFoos" and it has a pretty convinient meaning in the German language :p

Link: https://github.com/jAndreas/BarFoos


That is what its basically all about, read more about the project on github. I also worked a lot with Apache ANT to finally have one static build process which is cross platform available. BarFoos is still under heavy development and a 'living creature', but it's quite useable nonetheless. At present I'm rebuilding www.typeofnan.com which will be based on BarFoos.

Stay tuned and check back from time to time if you're interested in the future of web development (which is in my opinion => modularity).

Wednesday, April 6, 2011

Did you know.. Episode II

I finally recorded the second episode from "Did you know ?":



Topics:
- How to tweak .indexOf() with the bitwise not-operator
- How to determine if an image is "available"
- How to replace inline-javascript code with an unobtrusive version

Saturday, February 26, 2011

Did you know.. ?

After reading thousands of questions about Javascript, jQuery & Web development in general on Stackoverflow.com, I decided to create a little video blog about the most interesting ones.

So this is part one from "Did you know ?":



Topics:
- Firebug's Ctrl (Cmd) + return execute shortcut
- jQuery's node creation
- How to .sort() a jQuery wrappet set
- jQuery's setter callbacks
- jQuery's .selector property
- jQuery's fx queue methods trickery

I messed up some parts (for instance I kept saying 'property' where I was talking about attributes) I guess that is all about stage fright ;)

Tuesday, February 8, 2011

Data URIs & window.open()

I recently had the requirement, to open base64 encoded images in a new window. "Easy task" I said to myself, and just passed in the base64 encoded image source to window.open(). This works, since the .open() method can handle pretty much everything a browser can display. See MDC Doc Center.

However, this approach has a major downside. All the image data information goes right into the browsers address bar! Whaeerrhhg, not only this looks terrible, it will also slow down the action if you try to open some "big" base64 encoded images with this technique.

Example:


(You can execute a code snippet, by right-clicking it)

window.open("data:image/png;base64,R0lGODlhDQAOAJEAANno6wBmZgAAAAAAACH5BAAAAAAALAAAAAANAA4AQAIjjI8Iyw3GhACSQecutsFV3nzgNi7SVEbo06lZa66LRib2UQAAOw%3D%3D", "large");

So that was not an option, because I had to deal with lots of big images.
My idea was, not to pass an image data-uri directly, but to pass a data:text/html; string into window.open(), to magically create a little DOM tree in the newly created window. Looks like:

var largeprev = window.open('data:text/html;charset=utf-8,' + escape('
Hello, I was created through a data uri
'), 'large');

As we all know, window.open() returns a DOMWindow object. This reference can be used to access / modify the contents of that window (only restriction, the SOP (Same Origin Policy) will take effect here!)

So my plan was to do something like this:

jQuery('', {
    src: "data:image/png;base64,R0lGODlhDQAOAJEAANno6wBmZgAAAAAAACH5BAAAAAAALAAAAAANAA4AQAIjjI8Iyw3GhACSQecutsFV3nzgNi7SVEbo06lZa66LRib2UQAAOw%3D%3D",
    click: function() {
        var largeprev = window.open('data:text/html;charset=utf-8,' + escape('
'), 'large'), that = this; largeprev.addEventListener('DOMContentLoaded', function(e) { largeprev.document.querySelectorAll('div')[0].appendChild(that); }, false); } }).prependTo(document.body);

I could not wait to test the code. Opened Firefox (3.6.x.) and executed.. it worked great! Woohoo! Test it yourself here

I was pretty confident that this will work cross browser (at least, in all browsers that support Data-URIs), but to my shock neither Chrome(9) nor Safari (5) were able to run the above code.

The problem is, Webkit seems to treat the returned DOMWindow, like a foreign domain document. In other words, Chrome and Safari apply the SOP restrictions to a window, that was created with a Data-URI. AFAIK, a data: resource should inherit the "document.domain" from the environment in which it was encountered. I've sent a request for clarification to the whatwg already.

For now, the only working cross-browser solution, is to invoke document.write() like so:

jQuery('', {
    src: "data:image/png;base64,R0lGODlhDQAOAJEAANno6wBmZgAAAAAAACH5BAAAAAAALAAAAAANAA4AQAIjjI8Iyw3GhACSQecutsFV3nzgNi7SVEbo06lZa66LRib2UQAAOw%3D%3D",
    click: function() {
        var virtualdom = '',
            prev       = window.open('', 'large');

        prev.document.open();
        prev.document.write(virtualdom);
        prev.document.close();
    }
}).prependTo(document.body);

The above code does not get rendered correctly. The virtualdom variable looks different, see the code in Action.

---

Update:

I was just informed by a whatwg member, that there is an open ticket for Chrome at least:
http://code.google.com/p/chromium/issues/detail?id=58999

So, I guess this will get fixed in future versions.

Friday, January 28, 2011

mXHR Playground

Recently I extended supplyJS to support streaming images. (This actually was implemented all the time, I just added the listener for the MIME types)

I guess streaming javascript & stylesheet files is not expressive as streaming images (in terms of measurable performance). So now you can test it yourself:

http://www.typeofnan.com/lab/mxhr-stream/

I'd be more than happy to get some responses from you guys. If you're in the mood, please post your Browser / version / performance to the comments!

! Important !
To make this work, I'm using base64 encoded images. The Internet Explorer does not handle base64 encoded images that well, so it might not work (properly)

Thanks.

Monday, January 24, 2011

"typeof " is fast ?

Recently, I read an article about the such called "micro optimizations". The article was about when to use typeof and when just to check against the undefined value, if you want to know whether a variable/property is undefined or not.

The conclusion was, to use typeof for any "global" variable and a direct conditional check against undefined within the scope of a function where you know the variables are at least declared. That makes sense, because if( some_undefined_variable !== undefined ) throws a reference error.

I played around with that in mind and I thought, this might be interesting for fellow Javascripters. My first testcase looked like this:

var loops = 1e6,
    foo;

console.time('typeof');
while(loops--) {
    if( typeof foo !== 'undefined' ) {}
}
console.timeEnd('typeof');

loops = 1e6;

console.time('direct');
while(loops--) {
    if( foo !== undefined) {}
}
console.timeEnd('direct');

with the result of:

typeof: 421ms
direct: 603ms

Pretty interesting. So here it looks like, typeof is faster than just comparing a variable against undefined. I couldn't really believe what I've seen here. I thought that is probably because I'm in the global context and my Javascript engine (SpiderMonkey) does some kind of wierd scope chain lookups for "undefined". Anyway, it should improve the overall performance to put that code into a function (-context), which I did:

(function() {
    var loops = 1e6,
        foo;

    console.time('typeof');
    while(loops--) {
        if( typeof foo !== 'undefined' ) {}
    }
    console.timeEnd('typeof');

    loops = 1e6;

    console.time('direct');
    while(loops--) {
        if( foo !== undefined) {}
    }
    console.timeEnd('direct');
}());

Results:

typeof: 54ms
direct: 185ms

As expected, this has a better overall performance, but still typeof is way faster than a plain conditional check vs. undefined. Well, the important thing I forgot here is to keep a local reference (some people call it: cache) for the undefined value:

(function(undef) {
    var loops = 1e6,
        foo;

    console.time('typeof');
    while(loops--) {
        if( typeof foo !== 'undefined' ) {}
    }
    console.timeEnd('typeof');

    loops = 1e6;

    console.time('direct');
    while(loops--) {
        if( foo !== undef) {}
    }
    console.timeEnd('direct');
}());

Final results:

typeof: 51ms
direct: 38ms

Yay! That's the way to go and that's why you always should try to cache objects / object propertys before accessing (if its not a problem to have a static reference).
My default Javascript opener when using jQuery looks like:

(function(win, doc, $, undef) {
    // lots of beautiful code that can access win(window), 
    // doc(document), $(jQuery) and undef(undefined)
}(this, this.document, jQuery));

However, to be honest I'm still not 100% sure why this affects the undefined value that much. Cached references are faster to access (fact), totally makes sense for objects and propertys, but the undefined value is not a property as far as I know.

update:

I was wrong. undefined really is a property in the global object (window).

'undefined' in window; // = true

This explains why the cached version of the undefined value is way faster. Thanks to Stackoverflow member CMS who pointed me on this fact here.

Tuesday, December 21, 2010

supplyJS - Updated

I recently updated SupplyJS, hooray!

There are some minor fixes and changes along with a new feature. SupplyJS now caches transfered files into the localStorage (if available). The underlying principle is pretty easy, when the Supply dealerscript fetches the file contents, it checks the mtime (last modified) and compares it with the value the Supply Javascript passed over. This happens for each file.
So the frontend part looks into the localStorage and checks if there already is an entry for a specific file and if so, send it's mtime value to the dealer.

--Snippet--

if( settings & options.localStorage ) {
    for(i = 0; i < len; i++) {
        ret.push([n, '=', arr[i], '~', (arr[i] in localStorage) ? JSON.parse(localStorage[arr[i]]).modified : '0'].join('')); 
    }
}

The serverscript for that part looks like (example in perl)

($filename, $modified) = split(/~/, $file);   
   $mtime = (stat($javascript_dir . '/' . $filename))->[9];
  
   if( int($mtime) > int($modified) || int($modified) == 0 ) {    
    open (JSFILE, $javascript_dir . '/' . $filename) or next;   
    
    while(<jsfile>) {
     $jscontent .= $_; 
    }
    
    close JSFILE;
   }
   else {
    $jscontent = 'cached';
   }

..and finally, the listeners for javascript & stylesheet files were adapted:

self.listen('text/javascript', function(payload, filename, mtime){
   if( settings & options.localStorage ) {
    if( payload === 'cached' ) {
     payload = JSON.parse(localStorage[filename]).src;
    }
    else {
     setTimeout(function() { 
      localStorage[filename] = JSON.stringify({
       modified: mtime,
       src:  payload
      });
     }, cacheDelay += 300);
    }
   }
   
   try{
    if( settings & options.useeval ){
     eval(payload);
    }
    else {
     var head    = document.getElementsByTagName('head')[0] || document.documentElement,
      nscr    = document.createElement('script');
      
      nscr.type   = 'text/javascript';
      nscr[fillMethod] = payload;
      nscr.setAttribute('name', filename);
      
     head.insertBefore(nscr, head.firstChild);
     
     if( settings & options.removescripts ) head.removeChild(nscr);
    }
   } catch(err) {
    if( 'console' in window ) console.error(filename, ': Exception. Details -> ', err);             
   }
  });

As you can see, the localStorage access happens asynchronously with setTimeout. That timeout increases with each file to avoid too heavy disc operations after loading has completed.

I broke my promise to provide some more backend-scripts for Supply (so far!), but I didn't forget about it. Anyway I still would highly appreciate some support from you guys here. Any port of the backend part is very welcome.

Cheers,  Andy

https://github.com/jAndreas/Supply