I am trying to implement a SPA (single page application) without using any framework. I figured that I need to first download all my application resources (HTML, JS, CSS etc.) on my first page load and then use them later.
Now, since I have to pre-load resource and use it later, so I think I have 2 options:
Option 1: Download them using "script" or "link" tag etc. and then refer the downloaded resource later.
Option 2: Download then using xhr or jquery.get(), put them in a global variable and then use those global variables later.
Problems with options 1:
First and biggest challenge is how do I refer the downloaded resource later. Lets say I have somehow downloaded all my HTML, JS etc. but later, dynamically, how will I refer or read or load them later? I will read it from cache? But what if user has disabled caching of resources?
I know I can download JS files using <script> tag but how do I download HTML resource dynamically? I know some templating engine which can download but I do not want to use any external library.
Problems with options 2:
I could pretty much achieve this except below issues:
I downloaded my resources using jquery.get but since I wanted to refer them before DOM rendering so I couldn't use asynchronous mode. I had to download them synchronously. But then there is warning from XHR that synchronous downloading is deprecated. So, then how I can download a application resource synchronously?
I have to keep the content of downloaded resource in a global variable. So, I am worried that will it be a bad idea because it will consume my browser memory? How does the frameworks like Backbone.js or AngularJS does it?
Problems with options 1:
First and biggest challenge is how do I refer the downloaded resource
later. Lets say I have somehow downloaded all my HTML, JS etc. but
later, dynamically, how will I refer or read or load them later? I
will read it from cache? But what if user has disabled caching of
resources?
First of all, you can't directly download HTML using <script> or <link> tags as far as I know.
You can download scripts and css, the scripts will be compiled and executed once downloaded, and CSS will be applied to the web page. There is no need to refer to them later.
I know I can download JS files using <script> tag but how do I
download HTML resource dynamically? I know some templating engine
which can download but I do not want to use any external library.
In the above bullet you stated you can download HTML using <script> tags and now you're saying you can't in the very next bullet of same option. This is already answered, You can't.
Problems with options 2:
I could pretty much achieve this except below issues:
I downloaded my resources using jquery.get but since I wanted to
refer them before DOM rendering so I couldn't use asynchronous mode.
I had to download them synchronously. But then there is warning from
XHR that synchronous downloading is deprecated. So, then how I can
download a application resource synchronously?
"since I wanted to
refer them before DOM rendering" - consider DOM rendering is the process of downloading and processing the mandatory resources - resources that is needed to present the initial state, and load the resources that is going to be needed later. These will be downloaded by browser (think of the index.html and the <script> and <link> tag resources in it)
I have to keep the content of downloaded resource in a global
variable. So, I am worried that will it be a bad idea because it will
consume my browser memory? How does the frameworks like Backbone.js
or AngularJS does it?
There are techniques like name spacing, IIFE etc used to avoid global variables. And regarding memory, download the extra resources after the document is ready, when required. You wouldn't need any extra resources before document is ready.
Angular has some sort of optional cache, I haven't came across anything like that in backbone.
To conclude, simply load JS and CSS resources that are mandatory using <script> and <link> tags in index.html. And load any other resources required afterwards using AJAX, you wouldn't need to refer to JS or CSS since that is processed by the browser when injected via <script> and <link> tags. You can keep a reference to HTML strings simply using variables like var myHTML= ajaxResponse.
With all that said, look into libraries like requireJS, lazyload etc that already handles stuff like these.
Related
I keep having this doubt in my mind, I want to test if an URL exists before loading the script from that URL, but the way I'm trying to do it fails, as I'm using XMLHTTPRequests and as many know, when you use this method to GET a file from a server that it's not the same as the script that executes the GET, you will get back is not allowed by Access-Control-Allow-Origin .
So how come Modernizr.load() method can theoretically load the scripts and I cannot even see if there's actually something there ?
Because Modernizr.load(), like #dm03514 mentions, loads the script not through XMLHttpRequest, but by inserting a <script tag which doesn't have the cross-domain restriction. It then tries to check if the script loaded correctly, but that's not an easy task and it may not be possible in all browsers. For more detail you can see this recopilation of the support of different browsers for the various options available for checking success of loading scripts/css: http://pieisgood.org/test/script-link-events/
As for why XMLHttpRequest fails, you can read more about cross-domain restrictions at MDN: https://developer.mozilla.org/en-US/docs/HTTP_access_control
Some motivations for using script loaders are:
Loading scripts based on conditions like what yepnope and YUI do
Load scripts asynchronously for performance reasons ( tags block the rendering of the page).
Dependency injection (load resources that other scripts need, this is what requirejs does)
Load scripts when certain events happen (load hew functionality when a user clicks on a tab)
Also when you use script loaders, you usually load everything from them, including your application code, so that your application code has access to all dependencies. The require.js model (google AMD modules) is a great way of organizing your app. It allows you to write small modules that do specific tasks and reuse them, instead of one big file that does everything.
In my grails app, we use jquery. I include jquery on the necessary pages with
<g:javascript library="jquery"/>
If we decide to change javascript libraries, I need to update every page. I know I can include this in the layout, but the library is not needed on every page, so that seems wasteful.
Is there a typical way in grails to specify in one place what the default javascript library should be and then to just include that default one without specifying that it is jquery (or whatever it is) on every page?
Since most browsers heavily cache things like JavaScript libraries, putting the library include into the layout is probably better than putting it in each individual page. The heavy caching that browsers do means that users will only load the library from the server once for your whole site (or at least their browsing session), and by having it be handled in the layout you are drastically reducing your maintenance load (which you alluded to)
In general, your JavaScript libraries should be highly cached, and in many cases it's preferable to pull them from a highly used CDN, like Google's. Your "local" (ie. from your server) library should only get requested if the CDN provider goes down and the browser can't get to their library. (Take a look at the HTML5Boilerplate project for how this is done)
Because of that, I wouldn't worry about the very minimal performance hit that putting the library into the layout page would incur. Even if you don't use a well-used CDN for your library, any browser that people actually use today will only load your JavaScript library once (the first page it gets that includes it) and will simply use it's cached copy for the rest of the pages on your site.
So, in a nutshell, put it in the layout page and don't worry about it. It will only be requested on the first page load, and will come from the cache for all subsequent loads, and your codebase will be DRYer.
You could also create an external JS file that selectively loads the file(s) you specify. Something like this:
//FILENAME: jselector.js
if ( [conditions] ) {
var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src", filename); //reference your Jquery file here
document.getElementsByTagName("head")[0].appendChild(fileref);
}
Then put a reference to this file (jselector.js) in each of the pages that need it.
<script type="text/javascript" src="jselector.js"></script>
If your jQuery file ever changes, you update this single external JS (jselector.js), and all of the pages will automatically point to the new jQuery.
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.
I've been trying to build my own (small) framework in JavaScript for an AIR application and I've run into a peculiar problem: I can't find a way for a JavaScript file to load another. It seems the only way to load JavaScript is for an HTML file to load it.
Is this correct? Is there really no way for a JavaScript file to load another?
The security restrictions in Application Sandbox mode do not allow instantiating any new JavaScript code after the load event (during that event you can still load and evaluate JS).
As for the loading data, you should be able to use XHR to retrieve any text data you want at any moment of time without any restrictions.
Have you tried creating a script element, setting the src attribute, and adding it to the document body? I don't think the usual document.write() trickery works but I'm pretty sure adding a script element should.
(I believe all paths are relative to the root of the Air application itself.)
How to determine if a javascript was already loaded by other html file? I want to reduce the redundant loading of the javascript files to decrease the loading time of my webpages.
If your web server is providing correct caching headers this shouldn't be necessary, the browser will cache the javascript file across multiple requests.
You might want to check out the YDN page Best Practices for Speeding Up Your Web Site
If you want to prevent the files from being downloaded twice then this will be automatic provided they are set to be cacheable (most webservers should set these headers sensibly by default).
If you want to make sure that the include tag happens only once when including files in a dynamic language then you will need some sort of manager. ASP.NET provides a scriptmanager class that does this (among other things). I cannot speak for other languages and frameworks
As Rory says the second request will probably be cached, and noting that this is a bit of a design failure if it can happen, you can understand that the cached file is still going to execute with negative effect.
This is horrible, but you could wrap your JS script like this:
if (!document.foo)
{
//your script here
document.foo = true;
}