So someone shoulder-taps you and asks you to explain the concepts behind JavaScript Inheritance to them. In my eyes you’ve
got a few options.
The Terminology Play
You mention that it’s prototypal inheritance, not prototypical
and pretty much gloss over the rest, comfortable in your superiority in terminology. You may go as far as saying “Objects just
come from other Objects because there aren’t any classes.” Then you just link to
Crock’s Post on it, and try to seem busy for the next few days.
Many years later you find out that Prototypal and Prototypical are synonyms, but you choose to ignore this.
The Like-Classical-Inheritance-But-Different Play aka the Run-On Sentence Play
“So in Java, like, you have classes or whatever, right? Well so imagine that you don’t have those, but you still want to do
that same type of thing or whatever, so then you just take another object instead of a class and you just kind of use it
like it’s a class, but it’s not because it can change and it’s just a normal object, and if it changes and you don’t override
the object, oh yea, so you can decide to override the parent object class thing, so if you dont do that and the parent changes
the link is live…”
And so forth.
The Animal Play
This is a pretty popular one.
So let’s say we want to make an Animal class in our code. As is often necessary in production JavaScript applications.
First we make a “constructor function,” which acts kind of like a constructor method on the inside of a class in a classical
language when it’s invoked with the new operator. Except this one is on the outside.
Then we want to have actions that all animals can do.
123
Animal.prototype.walk=function(){console.log(this.name+' is walking.');};
But then you want to define a more specific type of animal. Things start to get weird.
1234567891011
// I think we need to define a new Animal type and extend from it somehowfunctionDog(name){this.name=name;}// BUT HOW DO WE EXTEND// WITHOUT AN INSTANCE TO USE?Dog.prototype=Animal.prototype;// ?? I HAVE NO IDEA// Maybe that'll work for some stuff?// ProHintâ„¢: probably not much, once you start modifying one of them :D
Then you remember that Prototypal Inheritance doesn’t really do ‘classes’ so much. So you do something like this:
12345678910
varDog=newAnimal('Annie');// ??? NO THATS NOT IT >:(// Maybe we can try Object.create? I hear it's prototypal-yvarDog=Object.create(Animal);// Maybe that worked? Let's see...varmyDog=newDog('Sparky');// TypeError: object is not a function// Shucks
And you eventually simply converge on the…
The Father/Son Analogy Play
Here we go. Finally a real world example of ‘instances begetting instances.’ It’ll be a perfect analogy.
It’s even an interview question some places. Let’s see how we might implement the relationship of a father
and son (or a parent to its child) in JavaScript.
We’ll start out like we did before, with a Human constructor
// Instantiate himvarmyDad=newHuman('Bill Sexton');// Greet himmyDad.sayHi();// "Hello, I'm Bill Sexton"
Score. Now let’s create me.
1234
// Let's use ES5 `object.create` in order to be as 'prototypal' as possible.varme=Object.create(myDad);me.sayHi();// "Hello, I'm Bill Sexton"
It’s a start! Seems like I inherited a little too much from my dad, but I inherited, none the less.
Let’s try to smooth things out to make the analogy work better. So we’ll instantiate objects without
a name and have a parent name them after they’re created.
1234567891011
// Wrap it all togetherfunctionmakeBaby(parent,name){// Instantiate a new object based on the parentvarbaby=Object.create(parent);// Set the name of the babybaby.name=name;// Give the baby awayreturnbaby;}
Perfect. Now the baby can sayHi on its own.
1234
varalex=makeBaby(myDad,'Alex Sexton');alex.sayHi();// "Hello, I'm Alex Sexton"
Err. yipes. Babies can’t talk. And what’s this deal with a baby being made by one parent. Not to worry,
we can fix all of this.
First we’ll probably want to try to take two parents into the makeBaby function (no giggles).
// Let's take a set of 4 genes for ease of// example here. We'll put them in charge// a few things.functionHuman(name,genes_mom,genes_dad){this.name=name;// Set the genesthis.genes={darkHair:this._selectGenes(genes_mom.darkHair,genes_dad.darkHair),smart:this._selectGenes(genes_mom.smart,genes_dad.smart),athletic:this._selectGenes(genes_mom.athletic,genes_dad.athletic),tall:this._selectGenes(genes_mom.tall,genes_dad.tall)};// Since genes affect you since birth we can set these as actual attributesthis.attributes={darkHair:!!(~this.genes.darkHair.indexOf('D')),smart:!!(~this.genes.smart.indexOf('D')),athletic:!!(~this.genes.athletic.indexOf('D')),tall:!!(~this.genes.tall.indexOf('D'))};}// You don't have access to your own gene selection// so we'll make this private (but in the javascript way)Human.prototype._selectGenes=function(gene1,gene2){// Assume that a gene is a 2 length array of the following possibilities// DD, Dr, rD, rr -- the latter being the only non "dominant" result// Simple random gene selectionreturn[gene1[Math.random()>0.5?1:0],gene2[Math.random()>0.5?1:0]]};Human.prototype.sayHi=function(){console.log("Hello, I'm "+this.name);};functionmakeBaby(name,mother,father){// Send in the genes of each parentvarbaby=newHuman(name,mother.genes,father.genes);returnbaby;}
Elementary. My only beef is that we no longer are using real prototypal inheritance.
There is no live link between the parents and the child. If there was only one parent,
we could use the __proto__ property to set the parent as the prototype after the
baby was instantiated. However we have two parents…
So we’ll need to implement runtime getters that do a lookup for each parent via
ES Proxies.
12345678910111213141516171819202122232425
functionmakeBaby(name,mother,father){// Send in the genes of each parentvarbaby=newHuman(name,mother.genes,father.genes);// Proxy the babyreturnnewProxy(baby,{get:function(proxy,prop){// shortcut the lookupif(baby[prop]){returnbaby[prop];}// Default parentvarparent=father;// Spice it upif(Math.random()>0.5){parent=mother;}// See if they have itreturnparent[prop];}});}
So now we support live lookups of parents, and, you know, some simplified genetics.
Isn’t that just a simple, well-defined, example of how straightforward inheritance can be in
JavaScript?
Conclusion
Sometimes these analogies get pretty crazy in my head, and I start to think that maybe
instead of trying to apply known examples in the outside world in order to help people
understand, it’s often better to just let someone know why they might wanna use
inheritance in their programs!
I personally find the best Prototypal Inheritance analogy to be:
1234567891011121314151617181920
vardefaults={zero:0,one:1};varmyOptions=Object.create(defaults);varyourOptions=Object.create(defaults);// When I want to change *just* my optionsmyOptions.zero=1000;// When you wanna change yoursyourOptions.one=42;// When we wanna change the **defaults** even after we've got our options// even **AFTER** we've already created our instancesdefaults.two=2;myOptions.two;// 2yourOptions.two;// 2
So stop making everything so confusing and go program cool stuff, and ignore
my old presentations when I used these analogies.
Preface: Nothing in this post is necessarily new, or even anything I thought of first (save for a name or two). However,
I’m writing it because I’d like to start building some consistency and naming conventions around a few of the techniques
that I am using (and are becoming more common), as well as document some processes that I find helpful.
Much of this comes from my experience deploying applications at Bazaarvoice as a large third party vendor, and should
probably be tailored to your specific environment. I’m sure someone does the opposite of me in each step
of this with good results.
Also, I fully understand the irony of loading a few MBs of GIFs in a post largely about performance,
but I like them. Any specific tools I mention are because I’m familiar with them, not necessarily because there
are no good alternatives. Feel free to comment on other good techniques and tools below. Facts appreciated.
You
You work on a large app. You might be a third party, or you might not be. You might be on a team, or you might not be.
You want maximum performance, with a high cache rate and extremely high availability.
The hope is that you have a way of taking your dev environment files and wrapping them up into concisely built and minified JavaScript
and CSS files. Ideally this is an easy step for you, otherwise, you’ll tend to skip it.
Optimize for ease of mind here. I tend to disagree with the sentiment that ‘script tags are enough.’ Try to manage your dependencies
in a single place, and that place probably isn’t in the order of your script tags in your HTML. Avoiding this step is easy until it isn’t.
Loading what you need is better than byte shaving
One technique at the build-stage that is ideal for performance, is building minimal packages based on likely use. At page load, you’ll want
to load, parse, and execute as little JavaScript as possible. Require.js allows you to “exclude” modules from your builds and
create separate secondary modules. Rather than shaving bytes
in your app files, you can avoid loading entire sections of code. Most sections of an app have predictable entry points that you can listen for
before injecting more functionality.
In our current app, only a fraction of the users click on the button that causes a specific flow to popup. Because of this we can
save ~20kb of code at page load time, and instead load it as a mouse gets close to the button, or after a few seconds of inactivity (to prime the cache).
This technique will go a much longer way than any of your normal byte saving tricks, but is not always the easiest and for that reason is often avoided.
Check your network panel the next time you have Gmail open to see how
Google feels about this technique. They take an extra
step and bring the code in as text, and don’t bother parsing or executing it until they need to. This is good for low-powered/mobile devices.
In fact, some Googlers released a library, Module Server, that allows you to do some of this dynamically.
It works with lots of module formats. And technically you could just use it to see how it decides to break up your files, and then switch
over to fully static files after you get that insight. They presented on it at JSConf.eu 2012:
So instead of using a microjs cross-domain communication library that your coworker hacked together, just delay loading EasyXDM
until you need to do cross domain form POSTs.
Don’t penalize modern users
I’m all for progressive enhancement, and have to support IE6 in our primary application. However, it pains me when modern browser users have to pay
a performance price for the sins of others. It’s a good idea to try to support some level of “conditional builds” or “profile builds.” In the
AMD world, you can use the has.js integration, or if you’re feeling especially dirty, a build pragma.
However, third-parties have written some pretty nifty tools for doing this as a plugin.
One of the best tools for this that I’ve seen is AMD-feature. It allows you
to use a set of known supported features to load the best fitting build for the current user. This can be great on mobile. You can silently switch
out jQuery with Zepto (assuming you stick to the shared subset). You can add and remove polyfills for the correct users. If 20% of your JavaScript
is loading for %3 of your users, something is backwards.
define({'dropdown':[{isAvailable:function(){// test if we are on iOSreturniOS?true:false;},implementation:'src/dropdown-ios'},{isAvailable:function(){// if we end up here, we're not on iOS,// so we can just return true.returntrue;},// Naturally this is simiplified and doesn't actually// imply Androidimplementation:'src/dropdown-android'}]});// In your code, you would load your feature like this:define(['feature!dropdown'],function(dropdown){// The variable 'dropdown' now contains// the right implementation - no matter// what platform the code is executed on,// and you can just do this:varmyDropdown=newdropdown();});
One less jpeg
Lots of people like repeating this one. I think Paul Irish coined itAdam J Sontag naturally coined it, but the idea is if that if you loaded one less jpeg on your
site, you could fit in quite a bit of unshaved JavaScript in its place. Consider this the next time you are sacrificing readability or compatibility for file size.
Requests matter
File size aside, the balance of a fast JS deployment lies somewhere between the number of requests, and the cachability of those requests.
It’s often alright to sacrifice the cachability of a small script if you can inline it without causing an additional request. The exact balance
is not one that I could possibly nail down, but you can probably think of a file that is dynamic enough and small enough in your application
that might make sense to just print it inline in your page.
Package all the pieces together
Fonts and Icons
These days, these two are synonymous. I really like using fonts as icons and have done so with great success. We try to find appropriate unicode
characters to map to the icons, but it can sometimes be a stretch. Drew Wilson’s Pictos Server is an incredible way
to get going with this technique, though I might suggest buying a font pack in the end for maximum performance (so you can package it with your
application).
First, we inline fonts as data URIs for supporting browsers. Then we fallback to referencing separate files (at the cost of a request), and then we fallback
to images (as separate requests). This means we end up with different builds of our CSS files. Each CSS build only includes one of the techniques,
so no one user is penalized by the way another browser might need fonts. The Filament Group has a tool for this called
Grunticon. I’d highly recommend this technique. For every modern browser, you have a single
request for all styles and icons, with no additional weight from old IEs that don’t support data-URIs.
CSS Files
It’s typically the case that updates to JavaScript files necessitate changes to CSS as well. So these files usually have the same update times. For that
reason it’s pretty safe to package them together.
So, as part of our build step, we first build our necessary CSS for our package into a file (for Bazaarvoice: styles are dependencies of templates,
which are dependencies of views, which are dependencies of the separate module packages we’re loading, so this is an automatic step). Then we
read this file in, minify it, and inject it as a string in our main JavaScript file. Because we have control over when the templates are
rendered, we can just inject the CSS into a style tag before rendering the template. We have to render on the serverside occasionally, as well,
and in these cases I would recommend against this technique to avoid a flash of unstyled content.
12345678910111213141516
varcss='#generated{css:goes-here;}';varhead=document.head||document.getElementsByTagName('head')[0],varstyle=document.createElement('style');style.type='text/css';if(style.styleSheet){style.styleSheet.cssText=css;}else{style.appendChild(document.createTextNode(css));}// Only assume you have a <head> if you control// the outer page.head.appendChild(style);
Since we inline the fonts and icons into our CSS files, and then inline the CSS into our JS file (of which only 1 is injected on load), we end up with
a single packaged app that contains fonts, icons, styles, and application logic. The only other request will be necessary media and the data (we’ll
get to those).
You may notice that we now have a couple of combinations of packages. Yep. If we have 3 ways to load fonts/icons multiplied by the number of
build profiles that we chose to create (mobile, oldIE, touch, etc), we can get 10-20 combinations fast. I consider this a really good thing. When you
generate them, have some consistent way of naming them, and we’ll be able to choose our exact needed app for a user, rather than a lot of extra
weight for other users.
Quick Note: Old IEs can be fickle with inlining a lot of CSS. Just test your stuff and if it breaks, just fall back to link tag injection for oldIEs.
The Scout File
This post actually started out as a means to solidify this term. Turns out I am a bit more long-winded than I anticipated.
The Scout File or Scout Script is the portion of JavaScript that decides which package needs to be loaded. It kicks off
every process that can happen in parallel, has a low cache time, and is as small as possible.
It gets its name from being a small entity that looks out of the cache from time to time to warn everybody else that things have
changed. It’s ‘scouting’ for an app update and gathering data.
// Simplified example of a scout file(function(){// Feature test some stuffvarfeatures={svg:Modernizr.svg,touch:Modernizr.touch};// The async script injection fanfarevarscript=document.createElement('script');varfScript=document.getElementsByTagName('script')[0];varbaseUrl='//cool-cdn.com/bucket/'+__BUILDNUM__+'/';// Build up a file url based on the features of this uservarfeatureString='';for(variinfeatures){if(features.hasOwnProperty(i)&&features[i]){featuresString+='-'+i;}}varpackage='build'+featureString+'.js'// Set the URL on the scriptscript.src=baseUrl+package;// Inject the scriptfScript.parentNode.insertBefore(script,fScript);// Start loading the data that you know you can grab right away// JSONP is small and easy to kick off for this.vardataScript=document.createElement('script');// Create a JSONP Url based on some info we have.// We'll assume localstorage for this example// though a cookie or url param might be safer.window.appInitData=function(initialData){// Get it to the core application when it eventually// loads or if it's already there.// A global is used here for ease of examplewindow.comeGetMe=initialData;};// If we're on a static site, the url might tell us// the data we need, and the user cookie might customize// it. Simplified.dataScript.src='//api.mysite.com'+document.location.pathname+'?userid='+localStorage.getItem('userid')+'&callback=appInitData;';// Inject itfScript.parentNode.insertBefore(dataScript,fScript);})();
If you’re a third party or have little control over the pages you’re injected on, you’ll probably use a file. Otherwise, the code
should be small enough and dynamic enough to warrant inlining on a page.
Build apps into self-contained folders
When you build your application, you end up with a set of static files in a folder. Take this folder of files and assign a build number to it.
Then upload this to a distributed content delivery network. S3 with CloudFront
on top of it is an easy choice. The Grunt S3 Plugin is a good way to do this with the Grunt toolchain.
Bazaarvoice has an Akamai contract, so we tend to use them, but the idea is that you are getting your built files onto servers that are geographically
close to your users. It’s easy and cheap. Don’t skimp! Latency is king.
Now that you have an app on a static CDN, make sure it gets served gzipped (where appropriate, grunt-s3 can help with this), and then set the cache
headers on your built files to forever. Any changes will get pushed as a different set of built files in a totally different folder, these
files should be guaranteed to never change. The only exception to this rule is the Scout File, which lives outside of the build folders in the root
directory.
The scout file for our third-party app is a very small JS file that contains a build number and a bit of JavaScript to determine the build profile
that needs to be loaded. It also contains the minimum amount of code to determine the initial data that we’re going to need for a page. It doesn’t
have jQuery, or really any dependencies, it just does exactly what it needs to do. This file is cached for about 5 minutes (should be relatively short, but
close to the average session length).
Parallelizing the initial data request
Many people use each of their models to make separate requests for data once the app is loaded. Unfortunately, this is terrible for performance. Not only
are there multiple requests, but they can’t be fired off until the BIG app files are loaded and executed. We want to parallelize the loading of our app
and our data. This is going to be tough for some folks, but it’s a huuuge performance win.
We use node.js to run our models at build time. We feed in each of the “page types” that we know how to handle. For each of these page types, each model registers
its intent to load data, and we build up a hash of data that is needed for each page type and stick that into the scout file.
Then we had our API folk create a batch API so we can make multiple data requests at once. We use this hash of needed data for each page type (we have less than
10 page types, and you probably do too) in order to fire off a single request for the data that all the models will need, before they are loaded. Unfortunately
the way to do this changes drastically based on your framework, but it’s worth your time!
Statically generate your container pages and CDN them too
If you aren’t rendering templates on the server, then there’s likely no reason you shouldn’t be statically compiling all of your page shells at their
appropriate urls, and uploading them to a static CDN along with your scripts. This is a huge performance improvement.
Distributing the HTML to geographically close servers can have big wins towards getting to your actual content more quickly. In the case that you are uploading your static HTML
pages up to the static cdn along with your JS Application, your HTML files can become your Scout File. Put a small cache on each static HTML
page and inline the contents that you would have put in a scout file. This serves the same purpose as before, except we’ve saved a request. The only thing
that isn’t highly cached on a close-by server is the data, and we’re already loading that in parallel with our app if we’ve followed the previous instructions.
This means the main URL for your site is just a CNAME to a Cloudfront url. Doesn’t that just sound nice? Talk about good uptime! Of course that
means the dynamic parts of your site would come from a subdomain like api.mysite.com or similar. The reduced latency of your initial HTML can be
a very nice win for performance since you’ve inlined a scout file to immediately load the rest of the app in parallel.
The smart peeps at Nodejitsu put out Blacksmith to help with static site generation a while
back, but there are plenty of options. Many apps are single page apps with
only an index.html file anyways, so you can skip the static generation all together.
All this together
The goal in all of this is to:
geographically cache anything that’s static, not just images and jQuery.
cache your app until it changes, but not much longer.
The folder structure I normally see is something like:
The index.html file is the only thing that changes, everything else is just added. If we’re a third party, it’d be the scout.js file since we’d be included in someone
else’s markup. Everything else has a 30yr cache header. We can upload our build into a folder, verify it, and then switch the build number in the scout file.
123
// Simplification of the above processvarbuild='__BUILD__';// Replaced at build timeinjectApp('/app/'+build+'/build.js');
Deploying a new version of the app becomes “updating one variable.” This means that every user on the site will have a fully updated app in the amount
of time you cached your scout file for. In our case it’s 5 minutes. It’s a pretty good trade off for us. We get lifetime caching for our big files and media,
but have a very quick turn around time for critical fixes and consistent roll-outs. It also means that if we ever need to roll back, it’s a single variable
change to get people fully back on the old code. Clean up old builds as you feel is necessary.
Other media requests
Naturally, you’ll have some logo images, or some promo images to load as part of the app. These should probably just be imageOptim‘d,
and sprited as best as possible. However, there is usually a second class of media on a site. Usually these are thumbnails and previews and avatars and such.
For these files, I’d suggest using a mechanism to lazy load these media files. Make sure you’re doing smart things with scroll event handlers (hint: throttling
the hell out of them), but you don’t want to load 50 avatars if the user is 1000px away from that part of your app. Just be smart about this stuff. It’s not
really my intent to cover this portion of app performance since it’s not entirely related to deployment.
Wrap Up
There’s nothing that surprising about these techniques. Everything that could possibly be statically generated is statically generated,
and thrown out on edge-cached servers. Every piece of functionality that isn’t needed on page load, isn’t loaded on page load. Everything that is needed
is loaded in parallel right away. Everything is cached forever, save for the scout file and the data request (you can save recent requests in local storage though!).
You aren’t left with much else to optimize. You are always only loading and executing the minimum amount of JavaScript, and saving it for the maximum amount
of time. Naturally the more common tips of not going overboard with external libraries, and paying attention to render performance, and serving HTML with the
page response are all ways to change the performance (usually for the better), but this architecture fits well with many of today’s more app-like deployments.
There’s something really comforting about exposing a minimal dynamic API that needs to be fast and having everything else served out of memory from nearby
static servers. You should totally try it.
The Jed Toolkit is a collection of interoperable tools to help facilitate
the full process of internationalizing applications in JavaScript.
These tools have a wide range of utility, from small modules to help
format messages, dates, and numbers to services that facilitate translation,
and code integration. The goal of the project is to bring the experience and
quality of internationalizing JavaScript applications up to par with the rest
of the current state of JavaScript tooling.
I’m excited that The Jed Toolkit has been accepted into the Dojo Foundation so
its users can be sure that it will be a safe, unencumbered resource for them
into the future. I’m extremely happy to be part of a family that includes
require.js, sizzle, and the dojo toolkit.
After being tasked with internationalizing a large application that I was building
I quickly realized that there was little available for JavaScript developers. I had
been using Gettext in a python application a few weeks prior, and decided it might be nice to
implement in JavaScript. So I did. I called it ”Jed” (soon to be gettext2.js) after
Jed Schmidt, everybody’s favorite “hobbyist” JavaScripter / Japanese translator.
I was drawn to this problem because there were so few people considering its intricacies, but
I was shown by some very smart folks that there was a lot more to internationalization than
the little library I wrote. So I wrote another library, and ported a few others.
I was quite happy with how these were turning out. They weren’t especially hard to create,
because most of them follow well-documented specifications. I really liked how ICU
MessageFormat made a lot of decisions based on how translators think, instead of how
programmers think. But naturally, they locked away that goodness behind a syntax/grammar
that no non-programmer should ever have to deal with. MessageFormat is great for translations
but not for translators. Not in the real world at least. That’s when I realized that the problem was not (only) the tools for writing
international apps, but even deeper: in the tools and integration with translators.
It’s all about tools
The translation space hasn’t grown much since computers first existed.
We can barely encode files correctly in 2012. However, in other spaces, like content authoring,
we have a whole system of tools and integrations to map non-technical users’ intent to structured
usable data for consumption. If your local tech writer wants to start a blog, they can! They
don’t need to know how to set up a server or that HTML even exists.
The process of getting an app translated is cumbersome, and is a blocker to getting
good applications out there. FTP zips and crazy XML specs mixed with Word Documents rule
the landscape. There are no decent apis, or automatic integrations that anybody is using
at scale. I want to set out to change this.
Translators aren’t all to blame. If you were a translator and got the message “fair”, would
you translate it as a carnival, or as ‘just’? We set our translators up for failure with
our context. We can do better. We can describe messages, and their variables. We can offer
examples and photos of the context. We can even translate the app in real time and they
can see their translation literally running in the place it will live.
The goal of the Jed I18n Toolkit is to help make the internationalization process much more
accurate and enjoyable for all parties. We should be able to write our messages directly in our templates
in whatever format we think is best. Our messages should be automatically culled, and deduped
and sent into a translation queue. The translator shouldn’t be presented with anything other than
things that help them translate. The programmer’s format should be irrelevant. Context is king, and
a bunch of crazy sprintf characters and html are just noise. When the translations are done, they should exist as
a service or api and be updated in real time. Gone should be the days of the 2 month translation code freeze.
You should be able to write a post commit hook that gets your translations through the system as fast
as you can find someone to translate them.
There’s a lot to decide on how to bring all of these ideas into the project in a generic, but still
usable way, and it will take some time to get everything right. Right now I’m starting by putting
in the few open source projects that are already out there as well as showing early beta work on some
of the integration tools. Please be patient with me and send me your suggestions and frustrations
so we can finally bring internationalization out of the dark ages.
At the end of last year I spoke at the awesome CapitolJS Conference in DC. I was encouraged to talk a little more broadly about third-party JavaScript development and its various quirks. When I got back home to AustinJS we had some time for a short talk. Luckily, Logan Lindquist is usually there to film talks for Austin Tech Videos. Long story short, my talk and slides are now available for Third Party JavaScript in the Third Person.
I work for a company called Bazaarvoice. Our core products (Ratings and Reviews is our biggest) are all implemented as third party javascript applications. We are white-label, so you don’t see a ton of our brand around, but we power the User Generated Content (UGC) behind Walmart, Samsung, Best Buy, Proctor & Gamble, etc, etc. Needless to say, we have one of the highest volume third party applications on the internet. Fun stuff. There are other massively successful and smart companies doing similar things (take a look at Disqus or even peek into the Google or Facebook button code).
Performance Matters
Our core applications were built nearly 7 years ago, and gained features everyday over that period of time. As you can imagine, performance started to suffer. Since we’re on the product page of major retailers, we knew that this wouldn’t stand. I was tasked with re-thinking our solution with performance at the forefront of our architectural and deployment strategies. I attacked three different types of performance at varying levels of depth.
Network
Injection/Rendering
Application
Bazaarvoice has a developer blog that I sometimes write for, so I wrote an article on Third Party Front-end Performance. Normally I don’t just link across, but I think this information is actually fairly applicable to a large chunk of developers. So check it out. Feel free to comment either place. Part 2 and 3 to come.