I watched a very interesting presentation from google the other day about this new technology called "Native Client". It looks and sounds very impressive. I'm glad to see Google is taking all the right steps to allow native code in the browser instead of jumping in head-first like Microsoft and creating an ActiveX clone which spawns security holes in our browsers for the next 10 years.
Below is a link to the official Native Client website as well as a presentation about it. The presentation goes for about an hour but is worth listening to as it gives a good insight into what they've already acheived and what their goals are for the project.
http://code.google.com/p/nativeclient/
http://www.youtube.com/watch?v=zgng4C18nNk
Monday, March 01, 2010
Tuesday, February 23, 2010
Benchmarking Google Maps
Recently I've been building a JavaScript API which wraps the the Google Maps API for both version 2 and 3. Its coming along very well and I've already unified most of the basic functionality into a simple to use API which is kind of a blend between the two versions.
The other day I was building in the marker support when a thought crossed my mind: "Has Maps 3 improved the rendering time for adding Markers to a Map?"
And so I went about setting up a benchmark to test it. It was a very simple test which uses firebug's profiler to monitor the "addMarker()" function call to add 1000 markers to a map. I performed the test identically in both versions of Maps. And the results? Amazing.
Well done Google Maps team!
The other day I was building in the marker support when a thought crossed my mind: "Has Maps 3 improved the rendering time for adding Markers to a Map?"
And so I went about setting up a benchmark to test it. It was a very simple test which uses firebug's profiler to monitor the "addMarker()" function call to add 1000 markers to a map. I performed the test identically in both versions of Maps. And the results? Amazing.
Version | Own Time | Total Time | Avg. Time | Min Time | Max Time |
---|---|---|---|---|---|
2 | 13.252ms | 14684.619ms | 14.685ms | 11.756ms | 238.471ms |
3 | 9.132ms | 287.789ms | 0.288ms | 0.274ms | 0.548ms |
Well done Google Maps team!
Wednesday, February 17, 2010
Extending Element Part 2
So as I mentioned at the end of my previous entry regarding extending Element in Internet Explorer; all my "hack" really did was replace one problem with another.
Now, at the moment I'm working on a Google Maps project and as you can probably imagine (or perhaps already know) there are a lot of DOM elements created by maps. For the solution in my previous blog entry, it is absolutely crippling trying to load a map. In fact, it took well over 5 minutes to render a single map. This project is for a client and so that kind of performance simply won't do.
I had to come up with another solution. It didn't take me too long to figure something out. I remembered from my time working with the Prototype JavaScript library that the developers there had figured out a way of extending it while maintaining performance in the browser. I also recalled that it wouldn't work in Internet Explorer unless the element had been extended with their element extension function which was usually done by the dollar function.
So I decided to follow this practice while applying my own sugar to the solution. And so here is the solution:
Now, at the moment I'm working on a Google Maps project and as you can probably imagine (or perhaps already know) there are a lot of DOM elements created by maps. For the solution in my previous blog entry, it is absolutely crippling trying to load a map. In fact, it took well over 5 minutes to render a single map. This project is for a client and so that kind of performance simply won't do.
I had to come up with another solution. It didn't take me too long to figure something out. I remembered from my time working with the Prototype JavaScript library that the developers there had figured out a way of extending it while maintaining performance in the browser. I also recalled that it wouldn't work in Internet Explorer unless the element had been extended with their element extension function which was usually done by the dollar function.
So I decided to follow this practice while applying my own sugar to the solution. And so here is the solution:
if (!window.Element)window.enableExtendElement;As for the Object.extend function. Well I'm sure you can figure that one out on your own ;)
$=function(element)
{
if (window.enableExtendElement && !element.__extended)
{
Object.extend(element,Element.prototype);
element.__extended=true;
}
if (Object.isElement(element))return element;
return document.getElementById(element);
}
Monday, February 15, 2010
Extending Element
For those of you that work with the web on a regular basis, you'll know that trying to program or design anything in internet explorer is like trying to get blood out of a stone.
The other day I spend a great many hours trying to tame the beast, and tame the best I have!!!
Microsoft, in all their wisdom, decided back in the day that extending any element on the page was totally uncool and blocked it to programmers. Now modern browsers such as Firefox, Chrome, Safari, Opera, Any-other-browser-except-IE6-and-7 actually allow the "Element" to be extended (Yes I didn't mention IE8 because someone at Microsoft got the memo for IE8 and allowed it).
My point is, after hours of hair pulling (yes, my own), I've created a simple HACK which uses another one of Internet Explorer's non-W3C-compliant technologies to bypass this ridiculous restriction. So if there is a way of getting around it, why not simply allow it in the first place... - Well done Microsoft, once again you've managed to leave me baffled, tired and out of patience - a state-of-mind which will take me weeks to get over.
I would really like to thank this website for giving me an idea for the foundation of this hack.
And so here it is. But be warned, it simply makes extending Element "work", the performance however, will make you cry.
The other day I spend a great many hours trying to tame the beast, and tame the best I have!!!
Microsoft, in all their wisdom, decided back in the day that extending any element on the page was totally uncool and blocked it to programmers. Now modern browsers such as Firefox, Chrome, Safari, Opera, Any-other-browser-except-IE6-and-7 actually allow the "Element" to be extended (Yes I didn't mention IE8 because someone at Microsoft got the memo for IE8 and allowed it).
My point is, after hours of hair pulling (yes, my own), I've created a simple HACK which uses another one of Internet Explorer's non-W3C-compliant technologies to bypass this ridiculous restriction. So if there is a way of getting around it, why not simply allow it in the first place... - Well done Microsoft, once again you've managed to leave me baffled, tired and out of patience - a state-of-mind which will take me weeks to get over.
I would really like to thank this website for giving me an idea for the foundation of this hack.
And so here it is. But be warned, it simply makes extending Element "work", the performance however, will make you cry.
var seedElement=false;
if (Object.isUndefined(window.Element))
{
seedElement=true;
window.Element=function(){};
}
//Extend the Element prototype.
Element.prototype.hide=function()
{
this.style.display='none';
}
//... do more extending ...
if (seedElement)
{
var behaviors =[],
newCSS =document.createElement('style');
newCSS.id ='IE_ELEMENT_SEEDER';
newCSS.type ='text/css';
document.getElementsByTagName('head')[0].appendChild(newCSS);
for (var method in Element.prototype)
{
behaviors.push('this.'+method+'=function(){return Element.prototype.'+method+'.apply(this,arguments)}');
}
document.styleSheets[(document.styleSheets.length-1)].addRule('*','{behavior:expression('+behaviors.join(',')+')}');
delete newCSS,method;
}
delete seedElement;
Saturday, February 13, 2010
Long Time No Bloggin'
Its been awhile since I've blogged, but I plan to change all that. As one of my new years resolutions, I plan to make an effort to blog at least once a fortnight. Weather it be something I'm currently working on or some insight into a particular topic, it'll all be here.
Wednesday, February 11, 2009
Uploading Files from AIR
The Problem
You want to upload multiple files from within an AIR application without user intervention.
The FileReference class has an 'upload()' method for doing just this, however it requires the user to first browser for and select the files on their computer. This is user intervention, so we cannot use this class.
The URLRequest class accepts a URLVariables object as its 'data' property. The problem with this is that the POSTed variables are encoded using 'x-www-form-urlencoded' format instead of the 'multipart/form-data' format which is required for sending files. So we cannot use this method of sending files.
The Solution
Using the URLRequest class, we assign a ByteArray object to it's 'data' property.
The URLRequest class accepts asigning a byte array to it's 'data' property, which it then uses as the body of the POST. So the idea is to manually construct the body of a POST and store it into a byte array.
Sounds simple enough, but there are a few gotchas that need we need to consider.
First of all, we need to make sure that we first set the correct content type. The content type also needs to contain a boundary definition so that the body of the POST can be correctly read by whatever server we're sending it to.
Here is an example:
The next thing to consider is the format of the bytes that we'll be writing into the byte array. The safest thing to do is to write them as UTF using the 'writeUTFBytes()' method available on the ByteArray object. The actual file data however must be written as raw binary using the 'writeBytes()' method. Additionally, with each line that we write to the byte array, we must make sure that we insert new line characters. These could be '\n' or '\r\n' depending on your choice. Since I'm a windows user, I've chosen to use '\r\n'.
The final thing to consider is the content-type of the files that will become part of this POST request. Getting this wrong can have consequences depending on the server you're POSTing to. Some server's may be configured to reject files which don't have a correct file extension vs. content-type match.
Now lets look at how a file should look like within our POST body.
-----------------------------------ApawaB03x
Content-Disposition: form-data; name="Filedata[]"; filename="foo.bar"
Content-Transfer-Encoding: binary
Content-Length: 32543600
Content-Type: application/octet-stream
{raw binary data goes here}
---------------------------------ApawaB03x
So with all these things in mind, here is how we bring it all togeather.
Notice the getMimeTypeByExtension function call within the above code. That is obviously an example function. That function would be pre-written to do a look-up on a mime table and return the correct mime type according to the file extension.
Aside from that, everything else in that script will work in AIR without any tweaking. You also may want to add some event listeners to the 'loader' object so that you can fetch a response from the server.
You want to upload multiple files from within an AIR application without user intervention.
The FileReference class has an 'upload()' method for doing just this, however it requires the user to first browser for and select the files on their computer. This is user intervention, so we cannot use this class.
The URLRequest class accepts a URLVariables object as its 'data' property. The problem with this is that the POSTed variables are encoded using 'x-www-form-urlencoded' format instead of the 'multipart/form-data' format which is required for sending files. So we cannot use this method of sending files.
The Solution
Using the URLRequest class, we assign a ByteArray object to it's 'data' property.
The URLRequest class accepts asigning a byte array to it's 'data' property, which it then uses as the body of the POST. So the idea is to manually construct the body of a POST and store it into a byte array.
Sounds simple enough, but there are a few gotchas that need we need to consider.
First of all, we need to make sure that we first set the correct content type. The content type also needs to contain a boundary definition so that the body of the POST can be correctly read by whatever server we're sending it to.
Here is an example:
var boundary ='---------------------------------ApawaB03x';
var request =new air.URLRequest();
request.contentType ='multipart/form-data, boundary='+boundary;
The next thing to consider is the format of the bytes that we'll be writing into the byte array. The safest thing to do is to write them as UTF using the 'writeUTFBytes()' method available on the ByteArray object. The actual file data however must be written as raw binary using the 'writeBytes()' method. Additionally, with each line that we write to the byte array, we must make sure that we insert new line characters. These could be '\n' or '\r\n' depending on your choice. Since I'm a windows user, I've chosen to use '\r\n'.
The final thing to consider is the content-type of the files that will become part of this POST request. Getting this wrong can have consequences depending on the server you're POSTing to. Some server's may be configured to reject files which don't have a correct file extension vs. content-type match.
Now lets look at how a file should look like within our POST body.
-----------------------------------ApawaB03x
Content-Disposition: form-data; name="Filedata[]"; filename="foo.bar"
Content-Transfer-Encoding: binary
Content-Length: 32543600
Content-Type: application/octet-stream
{raw binary data goes here}
---------------------------------ApawaB03x
So with all these things in mind, here is how we bring it all togeather.
//Dummy files.
var files=
[
'C:\\sound.wav',
'C:\\music.mp3',
'C:\\picture.jpg',
'C:\\text.txt'
];
//Initiate objects and static variables.
var boundary ='---------------------------------ApawaB03x',
buffer =new air.ByteArray(),
loader =new air.URLLoader(),
request =new air.URLRequest();
//Setup the request.
request.contentType ='multipart/form-data, boundary='+boundary;
request.method ='POST';
request.url ='http://localhost/';
request.useCache =false;
request.cacheResponse =false;
//Loop through each file and add it to the buffer.
for (var i=0,j=files.length; i<j; i++)
{
var file =new air.File(files[i]),
fileContents =new air.ByteArray(),
fileStream =new air.FileStream();
if (!file.exists)
{
throw 'The file "'+files[i]+'" does not exist and cannot be uploaded.';
delete file,fileContents,fileStream;
}
else
{
fileStream.open(file,air.FileMode.READ);
fileStream.readBytes(fileContents,0,file.size);
fileStream.close();
var mimeType=getMimeTypeByExtension(file.extension);
if (!mimeType)mimeType='application/octet-stream';
buffer.writeUTFBytes
(
[
'\r\n',
'--'+boundary+'\r\n',
'Content-Disposition: form-data; name="Filedata[]"; filename="'+file.name+'"\r\n',
'Content-Transfer-Encoding: binary\r\n',
'Content-Length: '+file.size+'\r\n',
'Content-Type: '+mimeType+'\r\n',
'\r\n'
].join('')
);
buffer.writeBytes(fileContents,0,fileContents.length);
delete file,fileContents,fileStream,mimeType;
}
}
//Close off the buffer with one final boundary.
buffer.writeUTFBytes('\r\n--'+boundary+'--\r\n');
//Assign the buffer to the body of the request.
request.data=buffer;
//Finally initiate the request.
loader.load(request);
Notice the getMimeTypeByExtension function call within the above code. That is obviously an example function. That function would be pre-written to do a look-up on a mime table and return the correct mime type according to the file extension.
Aside from that, everything else in that script will work in AIR without any tweaking. You also may want to add some event listeners to the 'loader' object so that you can fetch a response from the server.
Sunday, November 16, 2008
Object Orientated JavaScript - Part 1
So its that time again when a project is drawing to a close and I'm beginning to clean up the codebase and make sure everything is in order.
Usually this is straight forward and it's the usual steps of: review code, refactor, bug fix, test, document etc. This process can take days, or depending on the amount of bugs and changed requested by the client, weeks or months.
The plan with this project from the very beginning was to build up a code base of varying libraries which would work together as a loose framework which could then be refactored into a more solid Framework.
This week I began the cleaning up process. I started with a review of the codebase that had been growing since a little over one month ago now. Some of this code came from an earlier iPhone Project which used a slapped togeather framework named 'iCore', while other code was borrowed from other libraries.
So I started with all the Object Orientation libs. We had been using a mixture of JavaScriptMVC's new classing engine with a few modifications and a Package and Namespace library.
The classing engine is the critical component in the entire framework and even application. That, mixed with packages and namespaces have enabled complete modularization of the codebase... But I felt it wasn't enough. The classing engine, although being a solid implementation (based off of John Resig's Simple Javascript Inheritance), wasn't enabling a lot of features that many experienced programmers have come to expect from any object orientated language.
In addition to this, it has a critical flaw in its design. I can't speak for all classing engine implementations out there, but from my experience JavaScriptMVC (and Simple Javascript Inheritance) and Prototype all suffer from this flaw. The flaw itself is fundemental to a 'class' truely being a class. What am I talking about? I'm talking about what happens when an instance of a class is created.
Now I'm quite sure that when a programmer uses the keyword new in their code, they expect to get something new. However this apparantly isn't the case with these other implementations. Allow me to demonstrate.
To demonstrate I'll use JavaScriptMVC as the classing engine.
Create class Foo
Clearly this is a major problem. new is not creating a completely new instance of the class. However, it is making a partially new instance. Basically, any object in that has any depth (ie. children), won't be correctly initiated as a new object within the class.
The problem is fundamentally to do with how JavaScript deals with passing things around. JavaScript passes primitive values, such as strings and numbers, by value while other more complex values, such as functions and objects, by reference. And that right there is the problem. Complex types are being pushed around by reference and there is no clear way to actually make a copy. There is a way to get around this however and so I decided to write my own classing engine with one of the goals being to beat this problem.
So a couple days past and I finished the new classing engine. Its a rock solid Object Orientated implementation. Its simple to use and as far as I can tell, surpasses most other JavaScript classing engines available today.
Core Features:
Firstly, I'm going to explain how I fixed the critical issue mentioned above. The way in which this can be fixed is to deep copy the object. Or in this case, the entire prototype. This is done by using a set of pre-existing functions that I had written, namely 'extend' and 'clone'.
These perform deep copying by looping over each property of a given object and recursively calling itself if it encounters another object. And this here is the secret. If you simply copy something by doing var x=y, then it's going to create a reference, however if you go deep and individually copy each property of y, then it'll create a copy. Lets look at an example.
Clearly there is a little bit more overhead with this approach. Unfortunately that is the cost of doing Object Orientated programming in a procedural language. There simply is no other way to make this work correctly.
Now depending on the implementation, the actual fix to make the class engine do this may be different. My implementation uses a function to act as the internal constructor (when you instantiate with new) and then calls the init method which acts as the user-land constructor. Before this is initiated, some stuff happens (namely the behaviors of Traits are handled).
The trick is to clone the prototype, make the required changes to the active instance (this), then restore the original classes prototype with the cloned prototype. This will restore the class back to its original form without breaking any existing or the currently initiating instance(s) of the class. Example:
I'm going to stop typing now because this is getting pretty long and I'd rather break it up. I'll do another entry soon and go into some details regarding other features in this classing engine.
Usually this is straight forward and it's the usual steps of: review code, refactor, bug fix, test, document etc. This process can take days, or depending on the amount of bugs and changed requested by the client, weeks or months.
The plan with this project from the very beginning was to build up a code base of varying libraries which would work together as a loose framework which could then be refactored into a more solid Framework.
This week I began the cleaning up process. I started with a review of the codebase that had been growing since a little over one month ago now. Some of this code came from an earlier iPhone Project which used a slapped togeather framework named 'iCore', while other code was borrowed from other libraries.
So I started with all the Object Orientation libs. We had been using a mixture of JavaScriptMVC's new classing engine with a few modifications and a Package and Namespace library.
The classing engine is the critical component in the entire framework and even application. That, mixed with packages and namespaces have enabled complete modularization of the codebase... But I felt it wasn't enough. The classing engine, although being a solid implementation (based off of John Resig's Simple Javascript Inheritance), wasn't enabling a lot of features that many experienced programmers have come to expect from any object orientated language.
In addition to this, it has a critical flaw in its design. I can't speak for all classing engine implementations out there, but from my experience JavaScriptMVC (and Simple Javascript Inheritance) and Prototype all suffer from this flaw. The flaw itself is fundemental to a 'class' truely being a class. What am I talking about? I'm talking about what happens when an instance of a class is created.
Now I'm quite sure that when a programmer uses the keyword new in their code, they expect to get something new. However this apparantly isn't the case with these other implementations. Allow me to demonstrate.
To demonstrate I'll use JavaScriptMVC as the classing engine.
Create class Foo
var Foo=Class.extendInitiate Foo twice and change a property of baz
(
{
baz:
{
item1: 'A.1',
item2: 'A.2',
},
init: function(){}
}
);
var foo =new Foo();If we were to now inspect both foo and foo2, we would expect to see foo.baz.item1 equal B.1 and foo2.baz.item1 equal A.1. However this is unfortunately not the case. Since foo.baz.item1 was changed every instance, including the base class' (Foo.prototype.baz.item1) have been changed.
var foo2=new Foo();
foo.baz.item1='B.1';
Clearly this is a major problem. new is not creating a completely new instance of the class. However, it is making a partially new instance. Basically, any object in that has any depth (ie. children), won't be correctly initiated as a new object within the class.
The problem is fundamentally to do with how JavaScript deals with passing things around. JavaScript passes primitive values, such as strings and numbers, by value while other more complex values, such as functions and objects, by reference. And that right there is the problem. Complex types are being pushed around by reference and there is no clear way to actually make a copy. There is a way to get around this however and so I decided to write my own classing engine with one of the goals being to beat this problem.
So a couple days past and I finished the new classing engine. Its a rock solid Object Orientated implementation. Its simple to use and as far as I can tell, surpasses most other JavaScript classing engines available today.
Core Features:
- Namespacing
- Extending
- Interfaces
- Traits
- Simple to use
- Behavioral Traits
- True Object Orientated Classing (new means new!)
Firstly, I'm going to explain how I fixed the critical issue mentioned above. The way in which this can be fixed is to deep copy the object. Or in this case, the entire prototype. This is done by using a set of pre-existing functions that I had written, namely 'extend' and 'clone'.
These perform deep copying by looping over each property of a given object and recursively calling itself if it encounters another object. And this here is the secret. If you simply copy something by doing var x=y, then it's going to create a reference, however if you go deep and individually copy each property of y, then it'll create a copy. Lets look at an example.
var foo=
{
item1: 'A.1',
item2: 'A.2',
item3: 'A.3'
}
//Create a copy by reference.
var bar=foo;
//Create a copy by value.
var baz={};
for (item in foo)
{
baz[item]=foo[item];
}
Now depending on the implementation, the actual fix to make the class engine do this may be different. My implementation uses a function to act as the internal constructor (when you instantiate with new) and then calls the init method which acts as the user-land constructor. Before this is initiated, some stuff happens (namely the behaviors of Traits are handled).
The trick is to clone the prototype, make the required changes to the active instance (this), then restore the original classes prototype with the cloned prototype. This will restore the class back to its original form without breaking any existing or the currently initiating instance(s) of the class. Example:
baseClass=function()I hope other JavaScript library maintainers see this and fix up their code. Its a simple fix which would eliminate a lot of head scratching by developers using the library.
{
//The first and most important thing to do is to make a clone of the class prototype.
var prototype=Object.clone(baseClass.prototype);
//Do stuff...
//Now restore the class prototype back to its original form.
baseClass.prototype=prototype;
//Finally, initiate the class.
this.init.apply(this,args);
};
I'm going to stop typing now because this is getting pretty long and I'd rather break it up. I'll do another entry soon and go into some details regarding other features in this classing engine.
Labels:
Class,
Interface,
JavaScript,
Object Orientation,
Trait
Subscribe to:
Posts (Atom)