I've seen a few ways that you can make a javascript file include other javascript files, but they all seem pretty hacky - mostly they involve tacking the javascript file onto the end of the current document and then loading it in some way.
Why doesn't javascript just include a simple "load this file and execute the script in it" include directive? It's not like this is a new concept. I know that everyone is excited about doing everything in HTML5 with javascript etc, but isn't it going to be hard if you have to hack around omission of basic functionality like this?
I can't see how it would be a security concern, since a web page can include as many javascript files as it likes, and they all get executed anyway.
The main problems with the current inclusion system (ie, add additional script tags) involve latency. Since a script tag can insert code at the point of inclusion, as soon as a script tag is encountered, further parsing has to more-or-less stop until the JS downloads and is executed (although the browser can continue to fetch resources in parallel). If the JS decides to run an inclusion, you've just added more latency on top of this - now you can't even fetch your scripts in parallel.
Basically, it's trying to solve a problem that doesn't exist (since JS can already tack on additional script tags to do an inclusion), while making the latency problem worse. There are javascript minifiers out there that can merge JS files; you should look into using those instead, as they will help improve latency issues as well.
Actually, YUI 3 solves this problem beautifully. Feel free to check out the documentation: http://developer.yahoo.com/yui/3/yui/#use (that's the specific Use function which does this magic). Basically it works like this:
You define modules
When you create the core YUI object with YUI(), you specify which modules your code needs
Behind the scenes, YUI checks if those modules are loaded. If not, it asynchronously loads them on the page.
I've also read that the jQuery team's working on something similar (someone back me up here).
As to the philosophical argument that it'd be nice if this was built in, I think that may be a good feature. On the other hand, the simplicity of javascript is nice too. It allows a much lower point of entry for beginning programmers to do their thing. And for those of us that need it, great libraries like YUI are getting better every day.
the requirejs project attempts to solve this problem, please see for example
http://requirejs.org/docs/why.html
(I don't use it yet, though)
Related
I'm a developer on a very large, many-page web app. We're making a push to improve the sanity of our javascript, so I'd like to introduce a module loader. Currently everything is done the old-fashioned way of slapping a bunch of script tags on a page and hoping for the best. Some restrictions are:
Our html pages are templated, inherited, and composed, such that the final page sent to the client brings together pieces from many different source html files. Any of these given files may depend on javascript resources introduced higher up the chain.
This must be achievable piecemeal. The code base is far to large to convert everything at once, so I'm looking for a good solution for new pages, and for migrating over existing pages as needed.
This solution needs to coexist on the same page as existing, non-module javascript. Some things (like menus and analytics) exist on every page, and I can't remove global jquery, for instance, as it's used all over the place.
Basically I'd like a way to carve out safe spaces that use modules and modern dependency management. Most tutorials and articles I've read all target new projects.
Requirejs looks like a decent option, and I've played with it a bit. Its fully async nature is a hindrance in some cases though - I'd like to use requirejs to package up global resources but I can't do that if I can't control the execution order. Also, it sucks to have the main function of a page (say, rendering a table) happen after secondary things like analytics calls.
Any suggestions?
That's a lot to ask for. :-) So here are my thoughts on this:
Usually, when you load a web page - everything that was being displayed is wiped so that the new incoming information does not interfere with what was already there so you really have only a couple of options (that I know of) where you can keep everything in memory in the browser and yet load new pages as needed.
The first (and easiest) way is to use FRAMES. These are not used much anymore from what I've seen but each FRAME allows you to display a different web page. So what you do is to make one frame use 100% and the second one use "*" so it isn't seen. You can then use the unseen frame to control what is going on in the 100% frame.
The second way is to use Javascript to control everything. In this scenario you create a namespace area and then use jQuery's getscript() function to load in each page as you need it. I did this once by generating the HTML, converting it to hex via bin2hex(), send it back as a javascript function and then unhexing it in the browser and applying it to the web page. If it was to completely replace the web page you do that and if it was an update to a web page you just inserted it into the HTML already on the web page. Any new javascript function always attaches itself to the namespace. If a function is no longer needed, it can be removed from the namespace to free up memory.
Why convert the HTML to hex and then send it? Because then you can use whatever characters you want to us (like single and double quotes) and it doesn't affect Javascript at all. There are fairly fast hex routines available on GitHub (see my toHex and fromHex routines).
One of the extra benefits of using getScript() is that it can sometimes also make it almost impossible for anyone to see your code then. A fluke in how getScript() works which is documented.
Because I have been around engineers for so many years, I know that if I don't provide context, I'm just going to get a hundred answers of the form "What are you trying to accomplish?" I am going to give the background which motivates my question. But don't confuse the background context for the question I am asking, which is specifically related to the JavaScript semantics that made object code uncacheable between padge requests. I am not going to give marks for advice on how to make my webapp faster. It's completely tangential to my question, which will probably only be answerable by someone who has worked on a JavaScript compiler or at least the compiler for a dynamic language.
Background:
I am trying to improve the performance of a web application. Among its many resources, it contains one enormous JavaScript file with 40k lines and 1.3million characters pre-minification. Post-minification it's still large, and it still adds about 100ms to the window.onload event when synchronously loaded, even when the source is cached client-side. (I have conclusively ruled out the possibility that the resource is not being cached by watching the request logs and observing that it is not being requested.)
After confirming that it's still slow after being cached, I started doing some research on JavaScript caching in the major browsers, and have learned that none of them cache object code.
My question is in the form of some hypothetical assertions based on this research. Please object to these assertions if they are wrong.
JavaScript object code is not cached in any modern browser.
"Object code" can mean anything from a byte code representing a simple linearized parse tree all the way to native machine code.
JavaScript object code in a web browser is difficult to cache.
In other words, even if you're including a cached JS source file in an external tag, there is a linear cost to the inclusion of that script on a page, even if the script contains only function definitions, because all of that source needs to be compiled into an object code.
JavaScript object code is difficult to cache because JS source must evaluated in order to be compiled.
Statements have the ability to affect the compilation of downstream statements in a dynamic way that is difficult to statically analyze.
3a. (3) is true mostly because of eval().
Evaluation can have side effects on the DOM.
Therefore, JavaScript source needs to be compiled on every page request.
Bonus question: do any modern browsers cache a parse tree for cached JS source files? If not, why not?
Edit: If all of these assertions are correct, then I will give the answer to anyone who can expound on why they are correct, for example, by providing a sample of JS code that couldn't be cached as object code and then explaining why not.
I appreciate the suggestions on how to proceed from here to make my app faster, and I mostly agree with them. But the knowledge gap that I'm trying to fill is related to JS object code caching.
You're right in that it's dynamically compiled and evaluated.
You're right that it must be.
Your recourse isn't in trying to make that compile-time smaller.
It needs to be about loading less to begin with, doing the bare-minimum to get the user-experience visible, then doing the bare minimum to add core functionality in a modular fashion, then lazily (either on a timer, or as-requested by the end-user) loading in additional features, functionality and flourishes.
If your program is 10,000 lines of procedural code, then you've got a problem.
I'm hoping it's not all procedural.
So break it up. It means a slower 1st-page load. But on subsequent requests, it might mean much faster response-times as far as what the user perceives as "running", even though it will take longer to get to 100% functional.
It's all about the user's perception of "speed" and "responsiveness", and not about the shortest line to 100% functional.
JavaScript, in a single-threaded format, can't both do that and be responsive.
So be responsive first.
PS: Add a bootstrap. An intelligent bootstrap.
It should be able to discern which features are needed.
RequireJS is for loading dependencies.
Not for figuring out what your dependencies are.
An added benefit -- you can set a short-term cache on the bootstrap, which will point to versioned modules.
How is this a benefit? Well, if you need to update a module, it's a simple process to update the version in the bootstrap. When the bootstrap's cache expires, it points at the new module, which can have an infinite lifetime (because it's got a different name -- versioned or timestamped);
my rails applications (all 2.3.5) use a total mix of inline javascript, rjs, prototype and jquery. Let's call it learning or growing pains. Lately i have been more and more infatuated with unobtrusive javascript. It makes your html clean, in the same way css cleaned it up.
But most examples i have seen are small examples, and they put all javascript(jquery) inside application.js
Now i have a pretty big application, and i am thinking up ways to structure my js. I like somehow that my script is still close to the view, so i am thinking something like
orders.html.erb
orders.js
where orders.js contains the unobtrusive javascript specific to that view. But maybe that's just me being too conservative :)
I have read some posts by Yehuda Katz about this very problem here and here, where he tackles this problem. It will go through your js-files and only load those relevant to your view. But alas i can't find a current implementation.
So my questions:
how do you best structure your unobtrusive javascript; manage your code, how do you make sure that it is obvious from the html what something is supposed to do. I guess good class names go a long way :)
how do you arrange your files, load them all in? just a few? do you use content_for :script or javascript_include_tag in your view to load the relevant scripts. Or ... ?
do you write very generic functions (like a delete), with parameters (add extra attributes?), or do you write very specific functions (DRY?). I know in Rails 3 there is a standard set, and everything is unobtrusive there. But how to start in Rails 2.3.5?
In short: what are the best practices for doing unobtrusive javascript in rails? :)
I do not think there is one best practice, but I'll let you know what I do.
I have a series of js files each for with their own purpose in the public/javascripts/ directory. Some examples could be utility.js chat.js shopping_basket.js and so on.
I use asset packager and define one big fat collection for all my general use functionality and another for admin only functionality. Round trips to the server cost way too much. I basically include all the js in on first page load minified into one blob (in general)
I allow basic $(document).ready hooks inline in the pages, and keep them really short.
Data that my js files needs to access is rendered inline with the page. (Usually in the DOM, sometimes as vars - Eg. var xyz = 100)
I will usually develop my controllers with javascript off (and make sure it all works), then I turn it on and sprinkle a few if request.xhr? where needed.
Keep in mind, Rail 3.1 introduces a built-in best practice, see: http://guides.rubyonrails.org/asset_pipeline.html - on a personal note I have had performance and configuration issues with the new pipeline, however many others have had great success with it.
I recently documented how I have been managing javascript in Ruby on Rails. I basically break things down into many small, granular files, each with an appropriate namespace and then merge them all into a single file for production using asset_packager.
I found this post while trying to solve the same problem, but none of the existing solutions struck me as the right one. I wrote up my approach here. I love Rails' convention over configuration, so I wanted the same approach to including Javascripts that are applicable only to a particular action page. If nothing else, it's at least another approach to add to your options.
One of my co-workers is thinking that it is simpler to just include the document.ready() calls (MULTIPLE) for jquery anywhere in an html document, rather than trying to have them all in the head, foot or in an external js file. Can you give me your thoughts about this?
The document.ready stuff is loaded by modules that are included in a main template. I think this is messy. But I need a good argument point.
There are a number of problems with your coworker's approach:
It's not DRY. You must repeat the code each time you want to invoke it.
No ability to cache the same Javascript; it must be loaded with each new page.
If you decide to do it a different way later, N files are now different instead of one.
It will not be immediately obvious to a maintainer that this code is repeated across N different files.
Your coworker's approach is actually quite reasonable and pragmatic.
For the sake of completeness I'll point out that putting too much in ready() in the external JS file is a mistake. I started doing this once and ended up with a page load time of 500-1000ms with all this unnecessary JS code that was being executed. The external JS file(s) should be for declaring functions. The page itself should declare which of those things to actually run. This combines the best of minimal code execution and maximises caching (since the JS file is the same for all your pages).
At the top of the page you don't know what modules/components will be included in the document unless you declare it there as well, which (imho) is a worse case of repeating yourself.
The ideal approach would be some sort of multi-pass templating process that would allow included modules/components to trigger code that needs to be run and your template processor will combine all that and put it at the top of the page. I've actually written systems like this and it is quite doable but it's also more tedious.
You say it's messy but the other side of that coin is that when you look at a page it's easy to determine what code belongs to which module/component because they're adjacent. If you had a big blob of JS at the top of the page, how do you know what relates to what?
As long as you don't end up with dozens of script blocks I think your cowowrker's approach is fine. Any alternative needs to be just as clear and not execute more code than necessary.
If it's not single page specific, I wouldn't recommend it because maintenance is going to be a pain. If it is page specific, it can be better to place it as low in the document as possible, especially if it loads external scripts. Check out Cuzillion, a tool that helps you find the best combination for loading times.
If they're in the document itself, you can use server-side variables in the javascript itself, if your page is dynamic (php, asp.net). This can be very handy, but it prevents the javascript from being usable outside the page as a standalone. But if you're sure you're never going to need that javascript outside the page, that's definitely an advantage.
It depends.
One motivating factor for putting Javascript in the body is for progressive loading. If the Javascript is just before the </body> then it'll be downloaded last. In fact, even Google Analytics recommends this approach when including their tracking snippet.
However, most of the time even if you're worried about progressive loading you should use an external js file. External js files can be cached aggressively to save bandwidth so they're generally preferred. The only exceptions to that are when it's a small piece of Javascript that only one page uses, or if the Javascript itself needs to be created dynamically with a server-side language and writing it inline is just plain easier to do in that case.
EDIT:
There are multiple ways to do whatever you're doing, I'm sure. And I don't know what you're doing exactly. But since you mentioned Javascript next to every module, that gave me an idea. You could create unique id's for a div around each module. And then you could have a js file which performs operations on each module by those div id's (via a jQuery selector). That'd be a very jQuery-able solution.
I admit, I don't know too much about javascript, mostly I just "steal and modify" from Javascript.com and Dynamic Drive.
I've run across a few scripts that call two .js files
<script type="text/javascript" src="lib/prototype.js">
</script>
<script type="text/javascript" src="src/aptabs.js">
</script>
and was wondering why, can I safely merge them both with my external javascript or is there a sort of incompatibility that prevents all the code from sharing the same file?
It's often good to separate code with different concerns. Those two files might come from different places. Say prototype is upgraded and you want the new goodness. Then you can just replace the prototype.js file on your server rather than editing your huge file and do the surgery on it.
EDIT: It's also "nicer" for the browser to be able to cache the files individually. If your question comes from a concern of duplicating that block of code in several html files I suggest you make one snippet of it from the server side and include it your html files through whatever means you have at hand/feel comfy with.
It's actually better performance wise to have them both in the same file- Depending on how your site is architected. The principle is to reduce the number of http requests, as each one carries some overhead.
That said, that's something best left to the very end of production. During development it's easier to have everything seperate. If you're going to join them, it's best to have an automated build script to do the operations.
I'm pretty sure the javascript has no idea which file it has loaded from, so there shouldn't be a problem merging it, however...
Personally, I'd keep them separate. It will make it simpler to co-ordinate versioning etc. For most repeat visits, the script will be cached by the browser anyway, so 2 vs 1 isn't really a huge issue. But when you do upgrade one (or the other), the client only needs to download half as much. But again, since it is generally cached it isn't a biggie!
So for simplicity - keep the scripts in their original forms. Given your opening comment "I don't know too much about javascript", this is by far the best approach; I don't mean that disparagingly - simply that if something goes wrong, you don't want to have to find if you broke it, or it was broke already.
Edit: it also makes it easy to re-order, for example if you are using two scripts that use the same terminology like $ in jQuery, which also supports a mode with the explicit naming.