In an ASP.NET web application with a lot of HTML pages, a lot of inline JavaScript functions are accumulating. What is a good plan for organizing them into external files? Most of the functions are particular to the page for which they are written, but a few are relevant to the entire application.
A single file could get quite large. With C#, etc., I usually divide the files at least into one containing the general functions and classes, so that I can use the same file for other applications, and one for functions and classes particular to this application. I don't think that a large file would be good for performance in a web application, however.
What is the thinking in this regard?
You probably want each page to have its page-specific JavaScript in one place, and then all the shared JavaScript in a large file. If you SRC the large file, then your users' browsers will cache the JavaScript code on the first load, and the file size won't be an issue. If you're particularly worried about it, you can pack/minify your JavaScript source into a "distributable" form and save a few kilobytes.
Single file is large but is cached. Too many small files mean more requests to the server. It's a balancing act. Use tools like Firebug and YSlow to measure your performance and figure out what is best for your application.
There is some per-request overhead, so in total you will improve performance by combining it all into a single file. It may, however, slow down load times on the first page a user visits, and it may result in useless traffic if some user never require certain parts of your js.
The first of these problems isn't quite as problematic, though. If you have something like a signup page that everyone visits first and spends some time on (filling out a form, etc.), the page will be displayed once the html has been loaded and the js can load in the background while the user is busy with the form anyway.
I would organize the js into different files during development, i. e. one for general stuff and one per model, then combine them into a single file in the build process. You should also do compression at this point.
UPDATE: I explain this a bit more in depth in a blog post.
Assuming you mean .aspx pages when you indicate "HTML pages," here is what I do:
Let's say I have a page named foo.aspx and I have JavaScript specific to it. I name the .js file foo.aspx.js. Then I use something like this in a base page class (i.e. all of my pages inherit from this class):
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string possiblePageSpecificJavaScriptFile = string.Format("{0}.js", this.TemplateControl.AppRelativeVirtualPath);
if (File.Exists(Server.MapPath(possiblePageSpecificJavaScriptFile)) == true)
{
string absolutePath = possiblePageSpecificJavaScriptFile.Replace("~", Request.ApplicationPath);
absolutePath = string.Format("/{0}", absolutePath.TrimStart('/'));
Page.ClientScript.RegisterClientScriptInclude(absolutePath, absolutePath);
}
}
So, for each page in my application, this will look for a *.aspx.js file that matches the name of the page (in our example, foo.aspx.js) and place, within the rendered page, a script tag referencing it. (The code after the base.OnLoad(e); would best be extracted, I am simply trying to keep this as short as possible!)
To complete this, I have a registry hack that will cause any *.aspx.js files to collapse underneath the *.aspx page in the solution explorer of Visual Studio (i.e. it will hide underneath the page, just like the *.aspx.cs file does). Depending on the version of Visual Studio you are using, the registry hack is different. Here are a couple that I use with Windows XP (I don't know if they differ for Vista because I don't use Vista) - copy each one into a text file and rename it with a .reg extension, then execute the file:
Visual Studio 2005
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Projects\{E24C65DC-7377-472b-9ABA-BC803B73C61A}\RelatedFiles\.aspx\.js]
#=""
Visual Studio 2008
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\Projects\{E24C65DC-7377-472b-9ABA-BC803B73C61A}\RelatedFiles\.aspx\.js]
#=""
You will probably need to reboot your machine before these take effect. Also, the nesting will only take place for newly-added .js files, any that you have which are already named *.aspx.js can be nested by either re-adding them to the project or manually modifying the .csproj file's XML.
Anyway, that is how I do things and it really helps to keep things organized. For JavaScript files containing commonly-used JavaScript, I keep those in a root-level folder called JavaScript and also have some code in my base page class that adds those references. That should be simple enough to figure out. Hope this helps someone.
It also depends on the life of a user session. If a user is likely to go to multiple pages and spend a long time on the site a single large file can be worth the initial load seeing as it's cached. If it's more likely the user will come from google and just hit a single page then it would be better to just have individual files per page.
Use "namespacing" together with a folder-structure:
alt text http://www.roosteronacid.com/js.jpg
All you have to do is include Base.js, since that file sets up all the namespaces. And the .js file(s) (the classes) you want to use on a given page.
As far as page-specific scripts goes, I normally name the script according to the ASPX/HTML pages:
Default.aspx
Default.aspx.js
I would recommend that if you split your JS into seperate files, that you do not use lots of tags to include them , that will kill page-load performance. Instead, use server-side includes to inline them before they leave the server.
Related
I have a web application that is currently split into like 40+ javascript files. When I run the application some subset of those files need to be downloaded by the browser. Obviously, given that browsers use ~6 threads to download files, this is not the optimal solution. One optimization idea that come to my mind was to embed all those javascript files (except external ones) inside the served .aspx page. So that the browser just gets one big html file and does not need to make any round trips to the server. The html page alone may contain user specific data that will be different on every request. The scripts, however, are not changing between requests. In typical use case the page (complete with scripts) has 180KB (scripts not minified) or 130KB (minified).
Now the question: does this approach have any drawbacks performance wise (network, browsers' javascript engines)? Do you know of any big applications doing something like that? Note that I am not interested in arguments about eg. maintainability as the individual scripts will still be available as separate files during development. Same question applies to css files (even though this is less of an issue in my app).
One bit of information that may be important here: the application is one big multipage form that does not require postbacks to go between the pages, validate form, submit the form, etc. However, the application in which it is embedded may have multiple such forms.
In general, it is a very good idea to concatenate javascript and css files together. I'm just not so sure about "your concept". My biggest concern and question here would be, can that .aspx file change potentially in any way through (dynamic) code ?
That would make in impossible for the browser to cache the file, which would be a horrible scenario.
The great thing about concatenating files is, that we have one big downstream (which still is a lot faster then downloading with several single requests and HTTP overhead) and the browser can cache this file afterwards.
There are some great build-tools and scripts available, Apache ANT is one I can really suggest. You should have a look on the HTML5 Boilerplate where they make usage of ANT very frequently.
I've launched a redesign of our website and I'm using quite a bit of Javascript for the first time.
I've learned that I should be combining all my javascript and css into one file (each obviously) but while I know I can combine the css without problems but the javascript I'm not sure of.
I have to load:
jquery.min.js <-- I load the top two from ajax.googleapis.com, is that a good idea
jquery-ui.min.js
javascript for Facebook
some for google plus button
same for twitter
some for google analytics
then some inline stuff to hide divs which javascript users shouldn't see and that type of thing.
you can see it here: traditionalirishgifts.com
So can I just copy and paste the contents of all these files into one big file. Find some way to minify (haven't looked into that fully yet) it. Load this one file right at the bottom of my page before and bingo?
I'd use this tool: http://jscompress.com/
JSCompress.com is an online javascript compressor that allows you to
compress and minify your javascript files. Compressed javascript files
are ideal for production environments since they typically reduce the
size of the file by 30-90%. Most of the filesize reduction is achieved
by removing comments and extra whitespace characters that are not
needed by web browsers or visitors.
You should always be able to merge all your external JavaScripts into one file. You can use a server-side compressor to cache it and serve it as one file. It does put some constraints on the files, like which file should load first etc. Also, if there is a syntax error anywhere it will crash completely.
Keep in mind that 3rd party code like code from google can't be mixed in. Usually there is some kind of authentication going on (or an API key in the URL). If you try to cache that code, it will stop working after a while. So you do need to keep those separate.
Question
If you use a single javascript file to hold all scripts, where do you put scripts that are for just one page?
Background
This may be a matter of opinion or "best practice" but I'm interested in others' opinions:
I'm using the html5 Boilerplate on a project. They recommend you place all javascript in a single file script.js for speed and consistency. Seems reasonable.
However, I have a bit of geolocation script that's only relevant to a single page, and not others. Should I break convention and just put this script on the page below my calls to the javascript libraries it depends on? Just put calls to the relevant functions (located in the script.js) file, below the links to the libraries they depend on?
Thanks!
The good folks at html5 boilerplate recommend putting all of your javascript in script.js so that the browser will only have to load that one file (along with the others that h5bp uses) and to allow caching of that file.
The idea is not to get caught up in the "recommended" way, and to think about things related to your own applications.
This geolocation file is only going to be used on this one page, right? It will never be used anywhere else.
The script.js file will be used on multiple pages.
Well, then it wouldn't make sense to put a "whole script" that will only be needed on one page in the script.js file. You should make the file external and call it separately on the page that it is needed. This will keep you from bloating the script.js file for functionality that may never get used by that user.
However, if your "whole script" for the geolocation functionality is pretty small, then include it in script.js. If it doesn't add to the speed of the download for that file, then it makes sense to include it there.
The gist of all of this is, What is the best trade off for my application?
These things we know to be true:
cached js files are good
fewer files to download are good
smaller files to download are good
maintenance is important
Once you think of these things in terms of your application, the decision making becomes a bit easier. And remember, decisions that trade off milliseconds are not going to make much of a difference in your user's "perception" of how fast your page is.
The browser will only download the .js files once (unless something is happening to discourage the browser from caching). So if you expect all of your users to hit the one page that uses geolocation sometime during their session, then you might as well give it to them early. If you expect maybe a tiny percent of your users to eventually hit the geolocation page, then maybe you might want to split them.
Split it out into a separate .js file so that it can be cached. Then reference both external .js files from your page.
I think you should put it in a separate file. Putting all the scripts in one single file could cause unexpected behavior and conflicts. I like to have one script file for the javascript that all pages will use containing plugins, helper functions, formatting functions etc. And then create one separate js file for everything that is relevant just for each page.
If you still want to have just one js file in the browser you could take advantage of one of those utilities that combine multiple js files into one.
I have a couple of questions that are somewhat related so I'm posting them all on a single question on SO...
Question 1:
I'm currently doing this Facebook application where I'm using jQuery UI Tabs, there's only 4 where 2 of them are loaded through Ajax. The main page is index.html, this is where the tabs code is placed and for the 2 tabs loaded through Ajax, I have two different files, tab1.html and tab2.html.
Currently, the jQuery tabs initialization and Facebook JavaScript initialization is done on index.html. Both tab1.html and tab2.html have JavaScript code that belongs to those pages. For instance, tab2.html has a form and there's some JS (with jQuery) code to validate the form, this code is irrelevant to tab1.html as the JS code on tab1.html is irrelevant to tab2.html.
My question is, should I keep doing this or maybe aggregate all the JS/jQuery code in index.html, tab1.html and tab2.html in a single global.js file and then include it in index.html?
I though of doing this but there will be irrelevant code loaded if the user never opens tab1 or tab2. The benefit of using a single global.js file is that I could pack/minify the file, which I couldn't do if I included each code block in each respective tabX.html file.
Question 2:
As I'm using jQuery, I'm also using lots of plugins (actually only 3 for now, but that number can grow). Some of them provide a minified JS and I use those when available, when they are not, I use the normal versions of course.
There's also the requests problem. If I have lots of plugins, say 10, it will be 10 requests for those plugins. And there is also the fact that some plugins are used in tab1.html but not on tab2.html and vice-verse.
How should I load all the plugins in a minified/packed version on a single web request? Should I do that manually before publishing my app (packing and merging them into a single file) or could I use the PHP version of Dean Edwards's Packer and pack/merge all plugins on the fly? Would this be a good approach?
Question 3:
If the answer on Q1 was something like "merge all code in a single global.js file", should I include the global.js file in the packing/merging script I described above on Q2?
Doing this would simplify everything. I could have my development environment properly organized with all .js files, for the plugins and the global.js in the appropriate folders without bothering with anything else. The packing/merging should take care of the rest (pull the files from the respective folders, send the respective JS headers and output one single packed .js file).
The one thing that's confusing me the most is that not all plugins are used for every tab, not all code is for every tab too. Still, a chunk of the code is global to every tab and the index. This also simplifies everything as: a) I don't have to worry to add the needed code to each tabX.html file and can I simply look at them as HTML templates and nothing else; b) I don't have to be bothered in including the necessary plugins where I need them as I'm currently using $.getScript() from jQuery to load the plugins I need when and only when I need them, but I'm not sure this is a good approach and the code feels dirty and ugly like this.
Question 1:
Pack them all into a single .js file. This will make maintenance easier, and the tiny bit of overhead for the user loading a little js they they potentially may not use does not matter. I would also let Google load the jQuery library for you and then have all of your js code in a single separate file.
Question 2:
As these plugins don't really change I would manually combine them. Closure Compiler is good at this. When minifying use the highest setting that does not give any warnings.
Question 3:
Yes you will want to minify the global.js
When the browser downloads the global.js it's cached for an amount of time. Thus when you call the entire global.js again on a different page, its not re-downloaded it looks at your local copy first. So you do a little bit more work at first on the initial download, but from then on, it should be quicker.
Generally best practices related to javascript for speeding up website loads are:
Minify all javascript and put all of it into a single file (make as much of your javascript external as possible).
Put javascript at the bottom of the document.
Force web server to assign expiration date in the future and use a timestamped query string to invalidate old versions of javascript files, this will prevent unnecessary requests for your javascript if it has not changed. (ie: in httpd.conf ExpiresByType application/x-javascript "access plus 1 year", in your document: <script type="text/javascript" src="/allmy.js?v=1285877202"></script>)
Configure your web server to gzip all text files.
The main reason why you should keep too much javascript away from tab pages is because it will kill user experience. When a user clicks on a tab for the first time it will grab all the components needed on the fly which makes it kinda sluggish.
You're question is only semi-specific as we don't know a lot of things about your site like exact file sizes, how the modules are really used.
The general idea would be to find balance between modularity and speed.
When you're combining modules together these are the general ideas you should consider:
how often does this module change?
how often is this module used?
how big is this module (filesize)?
Then put the most used, stable codebase and merge it into one. Then you should include the rest site specific functionality on the tab pages.
Also, make sure to load javascript asynchronously as it won't block rendering of the page (and tabs).
Another combined answer:
if adding all the JS together in packed/minifed version generates no more than 30k of file size you're better off combining it. A single extra connection for a file (assuming it's not cached) is worth 10-20k of extra JS download. This has to do with browsers opening and closing connections vs streaming extra 20k on an established connection. The threshold also depends on your user distribution. If you have a lot of dial-up or low bandwidth users your threshold will be smaller.
I typically recommend combining and loading as 1 file unless the library is very obscure and requires a very edge case for it to be triggered on a page. Ex: Hover triggers functionality Y but it's on a feedback widget that gets less than 1% of traffic- don't bother combining.
Minifying and Packing is a little overrated these days. With the vast majority of browsers supporting gZip the amount of data consolidation gZip provides of the file over the wire during browser transmission has virtually the same effect as min/pack. However, there is a small cost on the browser to unpack it. Having said that, it's still good practice to min/pack the code since not all browsers support it, you may not want the file to be gZip enabled, etc.
I've used online packers against 3rd party module and it works fairly well. However, there are times when it can cause an issue so make sure to test your manually packed version before deploying.
Alternate:
If you feel that your users will rest on your index page for longer than 10 seconds you could pre-load the additional libraries separately using Js Loader Prototype pattern.
Steve Souder's Even Faster Websites is a book you should look into.
Firstly one experience slowdowns because whenever an external script is linked the browser waits for the script to download, parse and then execute. After this only it regains processing rest of the request. So to avoid such slow downs one can look at parallely downloading the scripts. Few techniques are Ajax the scripts if the scripts are in the same domain or use Script Dom element or Script in iframe if the scripts are on external domains
Q1 : For me modularising all the content is a better option with respect to further development if the page content has to be changed constantly. Responsiveness is very important for the end user. A small global.js will help in getting the app up and running.Parallely one can download the tabX.html.
Q2: As the jquery plugins rarely change. The plugins for the tabX.html pages can be downloaded parallely and locally cached so when the tabX.html is loaded the required plugins need not be fetched. SO all the plugins required by the main page should be in one single file and the ones used by the tabX.html's should be in different files.
Q3 : its a personal choice here. Do you want it to be developer friendly or user friendly. I bank on user friendliness. Making responsive and efficient apps is our job !!!. All the advantages of packing everything into a singe files is you will have ease in development. Well ugly code begets beautiful apps :). Users are speed-aholics. For eg. when google changed its 10 results per page to 20 they saw a considerable drop in search queries. So my opinion is not to pack all of them into one and load each parallely
some of the techniques and relevant links on testing each:
XHR eval /ajax : http://stevesouders.com/cuzillion/?ex=10009
XHR Injection : http://stevesouders.com/cuzillion/?ex=10015
Script in Iframe : http://stevesouders.com/cuzillion/?ex=10012
Script DOM element : http://stevesouders.com/cuzillion/?ex=10010
Question 1:
The best practice would be to place all js files in a single "global" file. This minimizes your HTTP Requests. Let's say you have 5 plug-ins, this would me you need to do 5 request, wherein if you combine them as one, you only need to request it once. This might be a little bit heavy on the first load, but the next time around this file will be cached by the browser, so..no worries about the size. HOWEVER, be careful about the sequence of the scripts when combining it. (I.E. : JQuery script should be placed first on the js file before JQuery UI's)
http://articles.sitepoint.com/article/web-site-optimization-steps/4
http://code.google.com/speed/page-speed/docs/rtt.html
Question 2:
You can do it manually or automatically.Dean Edward's Packer is a good choice. If you're using ASP.NET, you can check MB Compression Handler, if you're using APACHE with PHP perhaps you can change the configuration of your htaccess to gzip it
Question 3:
It'd be better if you pack the "global" javascript file as well. This could save up bandwidth and save more time to load. You got the point, combining all the js files you need for the site will save you time from including individual scripts.
Do you localize your javascript to the page, or have a master "application.js" or similar?
If it's the latter, what is the best practice to make sure your .js isn't executing on the wrong pages?
EDIT: by javascript I mean custom javascript you write as a developer, not js libraries. I can't imagine anyone would copy/paste the jQuery source into their page but you never know.
Putting all your js in one file can help performance (only one request versus several). And if you're using a content distribution network like Akamai it improves your cache hit ratio. Also, always throw inline js at the very bottom of the page (just above the body tag) because that is executed synchronously and can delay your page from rendering.
And yes, if one of the js files you are using is also hosted at google, make sure to use that one.
Here's my "guidelines". Note that none of these are formal, they just seem like the right thing to do.
All shared JS code lives in the SITE/javascripts directory, but it's loaded in 'tiers'
For site-wide stuff (like jquery, or my site wide application.js), the site wide layout (this would be a master page in ASP.net) includes the file. The script tags go at the top of the page.
There's also 'region-wide' stuff (eg: js code which is only needed in the admin section of the site). These regions either have a common layout (which can then include the script tags) or will render a common partial, and that partial can include the script tags)
For less-shared stuff (say my library that's only needed in a few places) then I put a script tag in those HTML pages individually. The script tags go at the top of the page.
For stuff that's only relevant to the single page, I just write inline javascript. I try to keep it as close to it's "target" as possible. For example, if I have some onclick js for a button, the script tag will go below the button.
For inline JS that doesn't have a target (eg: onload events) it goes at the bottom of the page.
So, how does something get into a localised library, or a site-wide library?.
The first time you need it, write it inline
The next time you need it, pull the inline code up to a localised library
If you're referencing some code in a localized library from (approximately) 3 or more places, pull the code up to a region-wide library
If it's needed from more than one region, pull it up to a site-wide library.
A common complaint about a system such as this, is that you wind up with 10 or 20 small JS files, where 2 or 3 large JS files will perform better from a networking point of view.
However, both rails and ASP.NET have features which handle combining and caching multiple JS files into one or more 'super' js files for production situations.
I'd recommend using features like this rather than compromising the quality/readability of the actual source code.
Yahoo!'s Exceptional Performance Team has some great performance suggestions for JavaScript. Steve Souders used to be on that team (he's now at Google) and he's written some interesting tools that can help you decide where to put JavaScript.
I try to avoid putting javascript functions on the rendered page. In general, I have an application.js (or root.js) that has generic functionality like menu manipulation. If a given page has specific javascript functionality, I'll create a .js file to handle that code and mimic the dir structure on how to get to that file (also using the same name as the rendered file).
In other words, if the rendered page is in public/dir1/dir2/mypage.html, the js file would be in public/js/dir1/dir2/mypage.js. I've found this style works well for me, especially when doing templating on a site. I build the template engine to "autoload" my resources (css and js) by taking the request path and doing some checking for the css and js equivalents in the css and js directories on the root.
Personally, I try to include several Javascript files, sorted by module (like YUI does). But once in a while, when I'm writing essentially a one-liner, I'll put it on the page.
Best practice is probably to put it on Google's servers.
(Depends what you mean by "your" javascript though I suppose :)
This is something I've been wrestling with, too. I've ended up by using my back-end PHP script to intelligently build a list of required JS files based on the content requested by the user.
By organizing my JS files into a repository that contains multiple files organized by purpose (be they general use, focused for a single page, single section, etc) I can use the chain of events that builds the page on the back-end to selectively choose which JS files get included based on need (see example below).
This is after implementing my web app without giving this aspect of the code enough thought. Now, I should also add that the javascript I use enhances but does not form the foundation of my site. If you're using something like SproutCore or Ext I imagine the solution would be somewhat different.
Here's an example for a PHP-driven website:
If your site is divided into sections and one of those sections is calendar. The user navigates to "index.phhp?module=calendar&action=view". If the PHP code is class-based the routing algorithm instantiates the CalendarModule class which is based on 'Module' and has a virtual method 'getJavascript'. This will return those javascript classes that are required to perform the action 'view' on the 'calendar' module. It can also take into account any other special requirements and return js files for those as well. The rendering code can verify that there are no duplicates of js files when the javascript include list is built for the final page. So the getJavascript method returns an array like this
return array('prototype.js','mycalendar.js');
Note that this, or some form of this, is not a new idea. But it took me some time to think it important enough to go to the trouble.
If it's only a few hundred bytes or less, and doesn't need to be used anywhere else, I would probably inline it. The network overhead for another http request will likely outweigh any performance gains that you get by pulling it out of the page.
If it needs to be used in a few places, I would put the function(s) into a common external file, and call it from an inline script as needed.
If you are targeting an iphone, try to keep anything that you want cached under 25k.
No hard and fast rules really, every approach has pros and cons, would strongly recommend you check out the articles that can be found on yahoo's developer section, so you can make informed decisions on a case by case basis.