Best practice for lazy loading in JavaScript - javascript

What's the best way to dynamically load HTML content and inject it in the page (when the HTML contains both <script src="..." /> tags and function calls to those scripts)?
Consider this approach (for simplicity, I will consider jQuery):
<script>
$.ajax({
url: 'http://...',
success: function(html) {
$("body").append(html);
}
});
</script>
Let's assume that the returned html contains something as such:
<script src="some_script.js"></script>
<script>
some_function(); // function defined in some_script.js
</script>
Since some_function() is defined in some_script.js it will be available only after some_script.js was loaded but (usually) it will be executed before some_script.js will be loaded (thus causing an error).
Obviously, there are some solutions to overcome this issue, but what is the best practice in this case? Should libraries such as RequireJS be used instead?
The example above is a result of the pattern I use: I have a component which I will load only when it's going to be used (at that point I make an Ajax call to retrieve both the HTML and the required scripts). Still, it can happen that many scripts are required and it's easier to write them as a set of tags in the HTML template rather than loading them through JavaScript (this is also preferred as the script URL may be generated inside the application so a plain JS script may not be aware of the absolute script URL).

Actually Safari and Internet Explorer (and most likely others) won't execute <script>'s that are injected through Ajax as a security measure.
What I can recommended is that when you need a library of considerable size (yet isn't required for actual use of your web application), is to rather load the .js-file containing the library into your document after which you can use all properties and methods defined in the library. Attach a callback listener to your script loader and execute all code in the callback, not in the external .js file itself.

Related

Load a script synchronously before render (programatically in <head>)

I have a javascript script that I want to load synchronously, but the URL of the script is determined by the value of a cookie. For example:
<script src="/js/[user-id-from-cookie].js">
This script has to load in the <head> of my HTML document and must be run synchronously (it has to block the main thread while it is downloaded and executed).
How can I use javascript to:
Read the value of a cookie
Download and execute the script synchronously
I need to do this in pure javascript, no frameworks like jQuery etc.
Thanks!
You can use document.write to load scripts synchronously.
But use it this way may cause some lag, I'd like to offer some alternatives.
parse the cookie and return different script per user by server. (recommended, but need to have server support)
load all the script, but rewrite them so only one would execute based on condition. (not good for large amount of variant, of course)
hide the body and only show after whatever preprocess have done. (not actually how to load script, but then you can load it asynchronously)

YepNope - Waiting until dependencies loaded

In a ASP.NET Masterpage I am using YepNope to unconditionally and asynchronously load jQuery (from the Google CDN, with local fallback) and some scripts which are used on all pages in the site. In the MasterPage I have created a ContentPlaceHolder before the closing body tag (and below the YepNope script that loads those used on all pages) which is used for scripts used on individual page. As jQuery should be available on every page in the site it should not be loaded individually on those pages where there are specific scripts that use it.
The problem I have is that I can't use the callback or complete functions in the yepnope script where jQuery is loaded, as this is on the MasterPage and these are individual page scripts which are only used or added on that page, yet I need to be able to delay the execution of the individual page scripts until yepnope (which appears above the page scripts) has finished loading any dependencies (such as jQuery) used in them.
I can think of two options-
1- Make the script used on the page an external file and load that using the syntax -
yepnope('/url/to/your/script.js');
or
yepnope({ load: '/url/to/your/script.js' });
I'm not sure I like this idea as it introduces an extra HTTP request for a few lines of javascript which isn't going to be used on any other page.
2- Load jQuery again in another yepnope test object block, with the complete function wrapping up the page scripts (calling complete without a test seems to execute the function immediately, before the previous scripts are loaded) and relying on the following-
I am requesting a file twice and it's only loading once? By popular
demand, in yepnope 1.5+ we added the feature that scripts that have
already been requested not be re-executed when they are requested a
second time. This can be helpful when you are dealing with less
complex serverside templating system and all you really care about is
that all of your dependencies are available.
In the page I could presumably load the same version of jQuery from the Google CDN, which based on the above would not actually be loaded twice, and then load the page scripts in an anonymous function called from the complete function of the yepnope test object.
On the plus side this would mean that the page is no longer dependent on jQuery being loaded from the MasterPage, but a negative would be that (even assuming YepNope does not load the script twice now) we would be loading multiple versions of jQuery should the version in the MasterPage be changed without the same happening in the page in the future. From a maintenance point of view I don't feel this is a good idea, especially on the assumption (which I feel you should always make) that another developer would be the one making the changes.
It also does not seem especially elegant.
On balance I will almost certainly use the first option but I would like to know if there is a way to delay or defer scripts on a page until asynchronous loading is completed, and this cannot be done as part of the YepNope test object loading the resources.
How do other developers approach this problem?
I have come up with this as a solution I rather like.
In the MasterPage YepNope test object add the code-
complete: function() {
if (window.pageFunctions !== null && typeof (window.pageFunctions) === "function") {
window.pageFunctions();
}
}
If I want to add any JavaScript code or functions that rely on the dependencies loaded in the MasterPage I just wrap them in a function named "pageFunctions" like so-
<script type="text/javascript">
function pageFunctions() {
$(document).ready(function () {
...
});
}
</script>
I'm still interested in other (possibly better) solutions so I'm going to leave the question open for a couple of days.
I'd also appreciate comments on this as a solution.

Read content of external script tag with jquery

A common pattern for loading backbone templates is something like:
<script type='text/template' id='foo'>
my template
</script>
----
var whatever = $('#foo').html();
I would like to include the script in an external file like so:
<script type='text/template' id='foo' src='myTemplate.tpl'></script>
But the html() of foo is now empty.
I watched the browser pull the template file down, but I am not sure if it is in the page dom or not. Is there a simple way to reference the content of the script in javascript, or did the browser simply ignore it and throw out the result?
I think to actually execute externally loaded script you have to do an eval() of the contents. You're not adding it to the DOM really since it's script, you're adding it to the JS runtime. There might be other ways of doing it but eval() is generally considered a security hole since malicious code could be evaluated.
What I tend to do is generate template sections on the server so I know all my JS is there when the DOM is ready.
If the point is execute an action just after the script has been loaded you can put a onload attribute on the script tag. If you want to download the content in runtime, then you could use the async download strategy (like Gats pointed).
It´s important keep in mind some important points when using templates for jquery templates in external files, there is an interesting article about jquery templates with external files, you must check it.

Using jQuery to send a variable to an external script and grab the results

I have a basic webpage set up and I would like to use jQuery to send a single variable (user-generated) to a javascript script (external -- well not really, still on the server, just not embedded in the webpage). This script will do a bunch of stuff with the variable and spit out a large array of results. I then need to update my page with the results.
I've done something similar using AJAX to POST stuff to a PHP script, but how can this be done with a JS script?
well ... including your script using the following (as opposed to embedding it) will keep your source neat and clean:
<script src="yourscript.js" type="text/javascript"></script>
The file could contain a function which you then call from outside (ie, the actual page source). As JavaScript is executed on the client-side (ie, the browser), downloading the file is unavoidable (unless you take extreme measures like an apache::mod_js, or rewrite the function in PHP). Best to keep things simple and use the above.
<script type="text/javascript" src="path/javascript_file.js"></script>
I think this is more what Kaustubh means. You do not have to put the actual code blocks into the page, just reference it this way.
When the page loads it will also load the javascript file (clean)
you can then call the functions seamlessly.

Are external scripts in the head of an HTML document guaranteed to execute before scripts contained within the body?

I'm trying to execute some inline javascript within an HTML page as early in page processing as possible that makes use of library functions in an external .js file.
While I've always seen that putting library scripts in the head, and client scripts in the body just seems to work, I can't find documentation anywhere that says that external scripts included within the head of a document are guaranteed to run before script located within the body of a document (except on the w3schools site, but they don't count as a reputable reference)
To illustrate, I'm wondering about the User-Agent behavior for HTML that looks like this:
<html>
<head>
<script type="text/javascript src="libraryModule.js"></script>
</head>
<body>
<script type="text/javascript">
// is this guaranteed to run after the external script?
// or is it possible this module that the external library
// adds to the global namespace won't be there yet?
var result = ModuleInExternalLibrary.DoLibraryThing();
</script>
</body>
</html>
Is this documented anywhere? I can't find anything in the W3C spec or any good post that sums up the behavior in this area of all the major browsers. Please provide a link.
Am I stuck having to wait until the onload event fires in order to guarantee that external scripts have executed?
JavaScript statements that appear between <script> and </script> tags are executed in order of appearance. So yes, it is guaranteed, unless you are doing something clever like deferred loading or something similar.
Execution of JavaScript Programs

Categories