When should I use Inline vs. External Javascript?

61,168

Solution 1

At the time this answer was originally posted (2008), the rule was simple: All script should be external. Both for maintenance and performance.

(Why performance? Because if the code is separate, it can easier be cached by browsers.)

JavaScript doesn't belong in the HTML code and if it contains special characters (such as <, >) it even creates problems.

Nowadays, web scalability has changed. Reducing the number of requests has become a valid consideration due to the latency of making multiple HTTP requests. This makes the answer more complex: in most cases, having JavaScript external is still recommended. But for certain cases, especially very small pieces of code, inlining them into the site’s HTML makes sense.

Solution 2

Maintainability is definitely a reason to keep them external, but if the configuration is a one-liner (or in general shorter than the HTTP overhead you would get for making those files external) it's performance-wise better to keep them inline. Always remember, that each HTTP request generates some overhead in terms of execution time and traffic.

Naturally this all becomes irrelevant the moment your code is longer than a couple of lines and is not really specific to one single page. The moment you want to be able to reuse that code, make it external. If you don't, look at its size and decide then.

Solution 3

If you only care about performance, most of advice in this thread is flat out wrong, and is becoming more and more wrong in the SPA era, where we can assume that the page is useless without the JS code. I've spent countless hours optimizing SPA page load times, and verifying these results with different browsers. Across the board the performance increase by re-orchestrating your html, can be quite dramatic.

To get the best performance, you have to think of pages as two-stage rockets. These two stages roughly correspond to <head> and <body> phases, but think of them instead as <static> and <dynamic>. The static portion is basically a string constant which you shove down the response pipe as fast as you possibly can. This can be a little tricky if you use a lot of middleware that sets cookies (these need to be set before sending http content), but in principle it's just flushing the response buffer, hopefully before jumping into some templating code (razor, php, etc) on the server. This may sound difficult, but then I'm just explaining it wrong, because it's near trivial. As you may have guessed, this static portion should contain all javascript inlined and minified. It would look something like

<!DOCTYPE html>
     <html>
         <head>
             <script>/*...inlined jquery, angular, your code*/</script>
             <style>/* ditto css */</style>
         </head>
         <body>
             <!-- inline all your templates, if applicable -->
             <script type='template-mime' id='1'></script>
             <script type='template-mime' id='2'></script>
             <script type='template-mime' id='3'></script>

Since it costs you next to nothing to send this portion down the wire, you can expect that the client will start receiving this somewhere around 5ms + latency after connecting to your server. Assuming the server is reasonably close this latency could be between 20ms to 60ms. Browsers will start processing this section as soon as they get it, and the processing time will normally dominate transfer time by factor 20 or more, which is now your amortized window for server-side processing of the <dynamic> portion.

It takes about 50ms for the browser (chrome, rest maybe 20% slower) to process inline jquery + signalr + angular + ng animate + ng touch + ng routes + lodash. That's pretty amazing in and of itself. Most web apps have less code than all those popular libraries put together, but let's say you have just as much, so we would win latency+100ms of processing on the client (this latency win comes from the second transfer chunk). By the time the second chunk arrives, we've processed all js code and templates and we can start executing dom transforms.

You may object that this method is orthogonal to the inlining concept, but it isn't. If you, instead of inlining, link to cdns or your own servers the browser would have to open another connection(s) and delay execution. Since this execution is basically free (as the server side is talking to the database) it must be clear that all of these jumps would cost more than doing no jumps at all. If there were a browser quirk that said external js executes faster we could measure which factor dominates. My measurements indicate that extra requests kill performance at this stage.

I work a lot with optimization of SPA apps. It's common for people to think that data volume is a big deal, while in truth latency, and execution often dominate. The minified libraries I listed add up to 300kb of data, and that's just 68 kb gzipped, or 200ms download on a 2mbit 3g/4g phone, which is exactly the latency it would take on the same phone to check IF it had the same data in its cache already, even if it was proxy cached, because the mobile latency tax (phone-to-tower-latency) still applies. Meanwhile, desktop connections that have lower first-hop latency typically have higher bandwidth anyway.

In short, right now (2014), it's best to inline all scripts, styles and templates.

EDIT (MAY 2016)

As JS applications continue to grow, and some of my payloads now stack up to 3+ megabytes of minified code, it's becoming obvious that at the very least common libraries should no longer be inlined.

Solution 4

Externalizing javascript is one of the yahoo performance rules: http://developer.yahoo.com/performance/rules.html#external

While the hard-and-fast rule that you should always externalize scripts will generally be a good bet, in some cases you may want to inline some of the scripts and styles. You should however only inline things that you know will improve performance (because you've measured this).

Solution 5

i think the specific to one page, short script case is (only) defensible case for inline script

Share:
61,168
user2161301
Author by

user2161301

Curiosity. Amoeba-shaped. Currently working on Moqups.

Updated on September 28, 2020

Comments

  • user2161301
    user2161301 almost 4 years

    I would like to know when I should include external scripts or write them inline with the html code, in terms of performance and ease of maintenance.

    What is the general practice for this?

    Real-world-scenario - I have several html pages that need client-side form validation. For this I use a jQuery plugin that I include on all these pages. But the question is, do I:

    • write the bits of code that configure this script inline?
    • include all bits in one file that's share among all these html pages?
    • include each bit in a separate external file, one for each html page?

    Thanks.

  • Lakhbir Chandel
    Lakhbir Chandel almost 16 years
    I think Yahoo also recommend adding all the Javascript into one HTTP call too - this doesn't mean that the scripts should all be in the same file during development though
  • user2161301
    user2161301 almost 16 years
    That's one of my concerns. Having a separate HTTP request for a few lines of codes seems wasteful.
  • Horst Gutmann
    Horst Gutmann almost 16 years
    Could you perhaps post a sample configuration for your code? IMO if it's under 300 characters and absolutely page-specific, inline it.
  • e-satis
    e-satis almost 16 years
    Agreed. And I'll add that you can put the < script > inclusion tag AT THE END of the html code as yahoo recommands it for performance reasons too (developer.yahoo.com/performance/rules.html#postload)
  • nickf
    nickf over 15 years
    @zach: putting a script tag in your HTML is not obtrusive JS. @konrad: you can easily overcome the < > problems by wrapping your code in a CDATA section.
  • Konrad Rudolph
    Konrad Rudolph over 15 years
    @Nick: most problems can be overcome. Better not to generate them in the first place, though.
  • Daniel Cassidy
    Daniel Cassidy almost 13 years
    @nickf There is no such thing as CDATA in HTML, and nobody ever serves their pages as XHTML even if they write XHTML in the DOCTYPE, because if they did their pages would not load in IE.
  • Konrad Rudolph
    Konrad Rudolph almost 13 years
    @Daniel I actually did this for one website, only non-supporting browsers (= MSIE) got a HTML doctype. That said, Firefox’ CDATA support was extremely buggy some time ago (no idea whether that’s changed).
  • callum
    callum about 12 years
    Sometimes you get better performance when inlining. Look at the source of google.com. They know what they're doing.
  • Konrad Rudolph
    Konrad Rudolph about 12 years
    @callum Google has a different use-case from 99.999999% of websites. Of course they measure extremely carefully and even the smallest difference matters. But just because they found that in their particular use-case, inlining works better (probably because the script changes very frequently?) doesn’t mean that we can derive a general rule from that, or even that we should disregard the “conventional” rule (to externalise scripts).
  • callum
    callum about 12 years
    @KonradRudolph - Agreed, no general rule should be derived from Google's approach. I'm just saying it's a hint that it might be worth questioning the rule in your answer. Anyway, I think the reason Google does it is to reduce HTTP requests, and this might benefit more than 0.000001% of sites. Bandwidth is getting higher but round trip times are staying the same. Removing a whole serial HTTP request is sometimes better than the caching benefit of external JS. Depends on the size of your JS of course.
  • Konrad Rudolph
    Konrad Rudolph about 12 years
    @callum While this is true, the point about caching still remains and stays important. Reducing roundtrips is only important if your visitors don’t return (and then you won’t get enough page hits to make it matter) or if your content changes so often that caching the script files has no benefit.
  • GorillaApe
    GorillaApe about 12 years
    then how are you going to have page specific stuff?
  • Konrad Rudolph
    Konrad Rudolph about 12 years
    @Parhs Load page-specific scripts. Or, if it’s a very small configuration, just have it inline.
  • Chris Marisic
    Chris Marisic almost 10 years
    -1 this a naive statement, there are certainly times where performance is greater inline vs http request (even cached).
  • Konrad Rudolph
    Konrad Rudolph almost 10 years
    @Chris … this has been discussed to death in the comments above.
  • machineaddict
    machineaddict over 9 years
    @Konrad Rudolph: Google does the opposite to whatever it recommends you, look at their websites. It's Google, deal with it!
  • Konrad Rudolph
    Konrad Rudolph over 9 years
    @machineaddict Exactly: it’s Google. You are not Google. Their guidelines are not for you. Also, I suggest you read the existing comments before commenting yourself the next time.
  • BornToCode
    BornToCode over 8 years
    I didn't get the which is now your amortized window for server-side processing of the <dynamic> portion part - The server processes what ever it needs and only then serves the entire rendered html (head+body), what other server processing is needed after that?
  • Gleno
    Gleno over 8 years
    @BornToCode The idea is to give client something to do at the same time the server side has something to do. Because the client libraries need to be interpreted - it's better to get that process started before doing any computation on the server. The amortized window is the time it takes the client to process the JS. You get that window for free, if you orchestrate a 2-stage rocket.
  • dev_willis
    dev_willis about 8 years
    Isn't the document cached just as easily as the javascript file? If you had a large number of pages each one would have to be cached but if you only had one page putting it inline saves the request. There's probably a point where the number of pages and size of the script makes saving the request less beneficial than caching a js file.
  • Konrad Rudolph
    Konrad Rudolph about 8 years
    @Dave If the page doesn't change. The whole point having separate files is to be able to cache some files when others change.
  • Vladd
    Vladd almost 8 years
    Disagree. Small script could and should be inlined performance wise. MOre xternal files, more calls.
  • Konrad Rudolph
    Konrad Rudolph almost 8 years
    @Vladd What do you mean by “more calls”? More HTTP requests/round-trips? Sure. And for high-traffic websites (Google, Stack Overflow, a handful more) that is totally an important metric. For 99.999% websites on the Internet, it’s utterly irrelevant.
  • Yuval Perelman
    Yuval Perelman about 7 years
    @Konrad, I completely disagree. The problem is not the "amount" of http calls, its the latency each call takes. At least according to my experience, the only thing that the end user really feels at the end is the round trips. unless all your clients live next door to the data center where your js is stored, or you are developing an intranet app, for 99.999% of the website that time is very relevant. what is usually irrelevant is the 1 - 300 kb more data you would need to transfer over the wire that could have been cached if the js would be separated
  • Konrad Rudolph
    Konrad Rudolph about 7 years
    @user2033402 If your end users feel the latency of loading external JavaScript, there’s probably an error in your server configuration (probably something that prevents concurrent loading). This shouldn’t (and indeed, doesn’t usually) happen.
  • Yuval Perelman
    Yuval Perelman about 7 years
    could be, or i'm just leaving in Israel, the main server is in the US and our clients are spread on all corners of the globe. we could of course invest money in replicating our website in many locations, but we like money and prefer to keep it for ourselves. yes, we could put our script in CDNs and remember to update them, we could do many things that takes money and time. Or we could just use inline scripts while we have no real reason not to. "shouldn't happen" on a general case is a funny word. I would like to reference you to Gleno's answer, looks like he came to the same conclusion
  • jinglesthula
    jinglesthula about 6 years
    @YuvalPerelman If the js is external and cached, the latency for the cached bits is ~0 on other than the first visit. With HTTP/2 many of the previous best practices don't apply anymore either, so which protocol is used should also be considered.
  • jinglesthula
    jinglesthula about 6 years
    @Dan bear in mind that the separate request only happens the first time. If you expect your users to be loading the page more than once, cached external (even for a few lines) is clearly faster than waiting for the bytes for those few lines over the wire on the n=2+ page loads.
  • jinglesthula
    jinglesthula about 6 years
    Also, as noted above, HTTP/2 changes the "1 call" practice as well.
  • jinglesthula
    jinglesthula about 6 years
    @KonradRudolph I am interested in what you said in your answer about external having a maintenance advantage. Can you elaborate?
  • jinglesthula
    jinglesthula about 6 years
    @HorstGutmann how does having the file external aid with maintainability? I personally prefer external js whenever possible, but is there something objective that makes it easier to maintain?
  • Horst Gutmann
    Horst Gutmann about 6 years
    @jinglesthula one example would be if you want to use the same code (or something quite similar) on multiple pages. Have the same code live in multiple places hinders maintainability. Sure, there are ways around that, but let's just assume the most naive implementation here. It's also far easier to statically analyse code when it lives in dedicated files (eslint et al.).
  • Yuval Perelman
    Yuval Perelman almost 6 years
    @jinglesthula why do you choose to ignore the first visit, which in many cases would be the only one? first visit is important, sometimes the most important. About maintenance, its much easier to maintain a script that is saved on a separate file, it gives you separation of concerns. HTML files (or php, cshtml etc.) tends to be large and hard to navigate, if you have scripts inside it can be dreadful. When you need to change something, its hard to find it, and the only way to update it is to update everything together. Until a certain degree, granularity is very convenient.
  • jinglesthula
    jinglesthula almost 6 years
    @YuvalPerelman I agree - the first visit is very important. I'm merely pointing out that on subsequent visits cached assets aren't fetched again, which is worth considering. Definitely, you need to consider your users' behavior. If 90% of your visitors only request the page once, that's very different than if 90% visit the page 2+ times.
  • jinglesthula
    jinglesthula almost 6 years
    re: maintenance advantage, I re-read and saw that this was referring to 2008 (before babel/es6 modules/react etc., and when HTML files really did typically contain large amounts of code). Now we can collocate all code for a concern - behavior (js), markup, and styles - in very small component files (certainly easier to maintain than when spread out over different files in different directories, and for js/css often mixed in with code for disparate concerns) so the thought of even trying to embed js in an HTML file is becoming a moot point. "js in my .html file? No! Put it with the markup!" :D
  • Ken Sharp
    Ken Sharp over 3 years
    Google lets scripts load before indexing.