Deferring dynamically added Javascript - javascript

I need to load some Javascript dynamically after the page has loaded.
Something like this:
page loads
page adds script element with src = "file1.js"
page adds script element with src = "file2.js"
file2.js has a dependency on file1.js - it adds properties to an object defined in file1.js
The problem is that file2.js is loading first (because it is smaller), and is immediately throwing an error because its dependency doesn't exist.
Is there a way for me to defer evaluation/execution of these new scripts until they have all loaded. (There is actually more than two scripts)
If I were to just embed these scripts in a page normally in authored HTML, then it seems that the browser loads all scripts, then evaluates them. But it is behaving differently because I'm adding script elements on the fly.
Thanks

There's a library called RequireJS that handles exactly this situation, and handles every situation you never realized were problems - http://requirejs.org/docs/start.html

Can't you wrap the contents of the files in functions and call them after everything has loaded?

Two suggestions for you:
Have a look at http://requirejs.org/ It solves this problem, among
others.
Or, roll your own simple js loader function. It would be a function that
uses ajax to load a script and then calls a callback when it's done.
Call this loader function in a nested way so that you load your
scripts in the right order.

Related

Less: `modifyVars` on files loaded after document loaded

My page uses Less files that are compiled on the client side. I want to load some of those files after page finished loading.
I tried the "Less in the browser" way, but it seems to only work for files that were originally declared in the head part of the page. Declarations I add later (from Javascript) are not processed by the Less...
Another way I tried was "Programmatic Usage", but in this case I have to inject the CSS code myself. It means I cannot use less.modifyVars() any more to change styling later (or I have to trigger recompilation myself and then replace the generated CSS, which I want to avoid).
I like the first way more, but I don't know how to load files after page finished initial loading. Maybe there is a function to load Less file?
Thank you!
I think I found solution:
less.registerStylesheets().then(
function () {
less.refresh();
}
);
First function will reread declarations. The second one will recompile all files (actually not very good).

RequireJS: how to control the execution sequence of the paralleled loaded js script

i have no doubts on the parallel scripts loading step, but i would like to know how RequireJS control the execution sequence of the parallel loaded scripts.
example defined as below.
<script data-main="js/main.js" src="js/require.js"></script>
main.js:
define(['a', 'b'], function() {
window.alert("scheduler loaded!");
})
how to ensure that a.js is executed before b.js?
and when the main.js is fetched and parsed for dependencies, how to deal with it later to let it show up in dom as script element without another http fetch. when we add script element to dom, there is always a http fetch(no cache enabled case), isn't it?
Your main.js script actually does get loaded as a <script> tag and run first; it's just that the function inside of it will not run until a and b are loaded. You do not need to add any script tags yourself if you are using requirejs.
To ensure a's content function runs before b's, simply define a as a dependency inside of b
// b.js
define(['a'], function(a) {
// use a for initiation here
}
If you add 'c' to that array, then c will also become an indirect dependency of main.js.
EDIT: In response to comment, this might give a better understanding. Each numbered item is one single HTTP request.
HTML retrieved
Requirejs itself is the first script seen, so that is loaded first.
Requirejs sees that its tag has a data-main attribute, and so retrieves main.js as a <script> tag. Once main.js has loaded, it would simply run the function on the inside of it, BUT, it looks like this file has dependencies (the array) that have not been loaded yet. SO, it creates <script> tags simultaneously for...
a.js
and b.js. Now, let's say this one finishes loading first - maybe a.js is really big. BUT! It looks like b has a dependency - on A. So, it won't run the inside function just yet. Requirejs knows that it's already waiting for a.js's script tag, so it won't send out a separate request for it - it can just wait on it. Once that loads, a's function runs, then b's, then main's.
No HTTP requests are wasted here - Requirejs sends out requests as soon as it's aware of a dependency, and doesn't request individual scripts multiple times, except in rare occasions when it has no way of knowing that something is going to be loaded.
An example of this rare occasion might be if SmallWidget.js is an individual dependency, compiled into a large file called BundleOfWidgets.js. (For a final build, many scripts are often wrapped into one) If one script requests BundleOfWidgets.js but then another script requests SmallWidget.js before that arrives, it won't know it's actually loading SmallWidget.js in a big package, and so it will retrieve that individual file on its own.

Load javascript file every time a new page is loaded

I'm using http://instantclick.io on my website (a pjax jquery plugin) and I'm experiencing some problems regarding javascripts. It's very temperamental - sometimes a page will load with all the scripting working fine, but other times parts of the scripts will not run. Also, scripts are running more than once. For example, if I set a console log in a .click() function, I'll see the console log multiple times when there should only be one.
In the instantclick.io documentation, it explains how to load a script on each page load:
If you have a snippet of JavaScript that you need to execute on every page change, use the following:
InstantClick.on('change', yourCallback);
But I need to run a whole js file rather than just a function. I have tried wrapping InstantClick.on('change', function(){ around my whole js file, but the scripts are still not running again after a new page is opened.
In my console, I'm seeing lots of errors relating to functions being undefined, which would indicate that the files are not being loaded each time.
How would I solve this? Thanks!
Write in callback code like this for adding js file dynamically to DOM
var jsFile=document.createElement('script');
jsFile.setAttribute("type","text/javascript");
jsFile.setAttribute("src", link);
document.getElementsByTagName("head")[0].appendChild(jsFile);
And change link to url path to your js file.
use it like this
long dateTimeSec = new Date().getTime();
<link rel="stylesheet" href="bootstrap/css/bootstrap.css?v=<%=dateTimeSec%>">

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.

How to automatically put JS files into a AJAX-called page?

Into my app I have included all needed JS files (my scripts, libraries such as Twitter Bootstrap etc.).
The problem is, that when I have a request which is called via AJAX, so in the called page are not included the JS files, which are included in my app and I have to include them into the called page.
Example: my_scripts.js contains lots of JS functions.
link to page called through AJAX
<a href="/articles/create_new" data-remote="true>Create New Article</a>
/views/articles/_create_new.html.haml
...some content of this file.. #here doesn't work the functions from the file "my_scripts.js"
when I put into the /views/articles/_create_new.html.haml this link
= javascript_include_tag "my_scripts"
...some content of this file..
so then in the /views/articles/_create_new.html.haml those JS functions working.
I would like to ask you, if exist any way, how to automatically put all JS files in my every single AJAX pages, because always include the JS files into an AJAX pages is not good way...
Thanks
use a script loader like RequireJS or $cript.
Have your pages reply 2 things also: the content and the scripts to load. This is best using JSON like:
{
"content" : "content here",
"scripts" : ["an","array","of","script","urls"]
}
then when the data is returned, parse and paint the content and after that, use the script loaders to load the scripts. Actually, you can make your own script loader. It's just a matter of dynamically creating a <script> tag, put it in the <head> and give it an src
I would achieve this in one of three ways:
jQuery
From http://api.jquery.com/load/:
Script Execution When calling .load() using a URL without a suffixed
selector expression, the content is passed to .html() prior to scripts
being removed. This executes the script blocks before they are
discarded. If .load() is called with a selector expression appended to
the URL, however, the scripts are stripped out prior to the DOM being
updated, and thus are not executed. An example of both cases can be
seen below:
Here, any JavaScript loaded into #a as a part of the document will
successfully execute.
$('#a').load('article.html');
However, in the following case, script
blocks in the document being loaded into #b are stripped out and not
executed:
$('#b').load('article.html #target');
Basically, you can add the JS references to the HTML returned by Ajax request and jQuery will execute them.
RequireJS or simular
Rather than return straight HTML, return the HTML as part of a JSON bundle that also contains an array of script references:
{
html: '<p>stuff</p>',
scriptRefs: [ 'js/one.js', 'js/two.js' ]
}
I would then iterate through the scriptRefs array with something like RequireJS.
Just add the code to base page
In all honesty, I'm more likely to just do this.

Categories