Loading one JS file before another - javascript

Ok so I have a .js file with about 10k lines of code. This code can be split up in
sub-object definitions
container object definitions
initialization code (after the objects have been defined)
program functionality
I would like to split this one file into 4 separate files, because it provides a better oversight. How do I go about doing this, given that they absolutely have to be declared in that order? What should I wrap up in a $(document).ready() and what not?
If I just separate the files and link them to the html in the correct order, I get undefined object errors. I was also thinking of something like this; but I don't know if that's any good...
Second JS File
function initializeContainers() {
var containerObj1 = {
bla: 'bla',
bla2: 'bla2'
},
var containerObj2 = {
bla: 'bla',
bla2: 'bla2'
};
};
First JS File
$(document).ready(function() {
function initializeSubObjects(callback) {
var subObj1 = {
somekey: 'somevalue',
someke2: 'someothervalue'
};
callback();
};
initializeSubObjects(initializeContainers);
});
I have no clue whether this is the correct way to do it?
PS: I also know you can add the script tags dynamically; but is that good practice?

In your example, you should swap the contents of your first and second file. You should only call the initializeContainers method when you know for sure the file has been loaded.
The easiest way to think about this is to load all files with definitions first (helpers, functions, classes, ...). Once all these are loaded, put the rest in the last file and start executing the code only in the last file
On a side note: If you deploy this into a production environment, you should consider bundling these files. Downloading 4 files will impact your load time, so it's better to just bundle them together and send them over as a single file. While you're at it, you probably also want to minify it.

Related

How to boot a multi-page app with Browserify and Gulp

Ok, I'm near to the finish line with my new PHP/JS app built with Gulp and Browserify. The last part is how to "boot", I mean how to do the "first call".
Let's say I have 3 JS entry points
/js/articles.js
/js/categories.js
/js/comments.js
each of them using some JS modules.
Then I have 3 HTML files, requiring their JS
/articles.html
/categories.html
/comments.html
example /js/articles.js
var $ = require("jquery");
var common = require("../common.js");
var viewModel = {
readData: function() {
/* read record from API and render */
},
insert: function() {
/* open a modal to insert new record */
}
};
What I should do now is to perform this sort of "boot": that is calling some init function I need, then load server data, then bind all buttons and stuff to viewModel's methods
$(document).ready(function() {
common.init();
viewModel.readData();
$('#btn-add').click(viewModel.insert);
});
Ok, but where am I to put this?
A) In HTML file?
I can't cause I don't have any global JS variabile to access..
B) Am I put it into articles.js?
At the moment, my Gulp task will bundle everything (articles.js, categories.js, comments.js, common libraries) into a single bundle.js.
If I put it into articles.js it will end up into the bundle.js. So articles-related boot stuff would be called in "categories" page either. And this is wrong.
C) Should I split articles.js into 2 files, one containing viewModel definition and the other doing the $(document).ready stuff?... but again how do I access to the correct viewModel?
Which is the correct solution?
Thank you
Seems your gulp task would just concat all the entries into bundle.js so you probably could just add another entry called js/index.js and put your initialization code inside it.
It's confusing that your code will be executed (base on your description in B) even though you don't call require on it. Can you provide your bundle.js and one of your html file?

Dynamically Included Javascript and Dependencies

So, as a sort of exercise for myself, I'm writing a little async script loader utility (think require.js, head.js, yepnope.js), and have run across a little bit of a conundrum. First, the basic syntax is like this:
using("Models/SomeModel", function() {
//callback when all dependencies loaded
});
Now, I want to know, when this call is made, what file I'm in. I could do it with an ajax call, so that I can mark a flag after the content loads, but before I eval it to mark that all using calls are going to be for a specific file, then unset the flag immediately after the eval (I know eval is evil, but in this case it's javascript in the first place, not json, so it's not AS evil). I'm pretty sure this would get what I need, however I would prefer to do this with a script tag for a few reasons:
It's semantically more correct
Easier to find scripts for debugging (unique file names are much easier to look through than anonymous script blocks and debugger statements)
Cross-domain requests. I know I could try to use XDomainRequest, but most servers aren't going to be set up for that, and I want the ability to reference external scripts on CDN's.
I tried something that almost got me what I needed. I keep a list of every time using is called. When one of the scripts loads, I take any of those using references and incorporate them into the correct object for the file that just loaded, and clear the global list. This actually seems to work alright in Firefox and Chrome, but fails in IE because the load events seem to go off at weird times (a jQuery reference swallowed a reference to another type and ended up showing it as a dependency). I thought I could latch on to the "interactive" readystate, but it doesn't appear to ever happen.
So now I come asking if anybody here has any thoughts on this. If y'all want, I can post the code, but it's still very messy and probably hard to read.
Edit: Additional usages
//aliasing and multiple dependencies
using.alias("ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js", "jQuery");
using(["jQuery", "Models/SomeModel"], function() {
//should run after both jQuery and SomeModel have been loaded and run
});
//css and conditionals (using some non-existant variables here)
using.css({ src: "IEFix", conditionally: browser === "MSIE" && version < 9 });
//should include the IEFix.css file if the browser is IE8 or below
and to expound more on my response below, consider this to be file A (and consider the jquery alias from before to be there still):
using(["jQuery", "B"], function() {
console.log("This should be last (after both jQuery and B have loaded)");
console.log(typeof($));
});
Then this would be B:
using("C", function() {
console.log("This should be second");
});
And finally, C:
console.log("This should be first");
The output should be:
This should be first
This should be second
This should be last (after both jQuery and B have loaded)
[Object Object]
Commendable that you are taking on such an educational project.
However, you won't be able to pull it off quite the way you want to do it.
The good news is:
No need to know what file you are in
No need to mess with eval.
You actually have everything you need right there: A function reference. A callback, if you will.
A rough P-code for your using function would be:
function using(modules, callback) {
var loadedModules = []
// This will be an ajax call to load things, several different ways to do it..
loadedModules[0] = loadModule(modules[0]);
loadedModules[1] = loadModule(modules[1]);
// Great, now we have all the modules
// null = value for `this`
callback.apply(null, loadedModules);
}

javascript strategy / best practice

I'm getting into writing some more complex javascript applications, and I'm running into the limitations of my own knowledge-- please forgive any naming errors or obvious noob stuff, I'm not a js pro!
I have about 4 or 5 scripts I've put in their own files, just to keep things a little easier to maintain. So maybe there's one script that deals with building page elements (like complex forms), another that just handles data, creating generic ajax request objects, defining parsers and error functions for the data returned, and another that is purely display-oriented.
I've set global variables in the page that then get populated by various scripts that get loaded at run time. For example, I define var myapp = { }; in the main HTML page, and then in the scripts various function populate this "namespace" like:
myapp.myfunction = function(){
// do stuff
}
The problem is that despite all the scripts including a $(document).ready(function() block that wraps all function definitions, when a function is called from one script that refers to another (that is, if my data.js file calls a function myapp.myDisplayFunction that is in the display.js file, I sometimes get an Object has no method 'myDisplayFunction'
Other than slamming all functions into one massive script, how do you deal with this problem? Is there a best practice that I'm missing? or is this just a question of specifying a different order that the scripts are called in?
Thanks
When you are not sure if method you are about to call exists (is already loaded) you can do a check:
if (myapp) //my app namespace is defined
{
if (myapp.myFunction) //myFunction is defined
{
myapp.myFunction();
}
else
alert('You have to load myFile.js first!');
}
Just check for the function before using:
if(typeof(myapp.myDisplayFunction) !== undefined) {
// do your stuff
} else {
// wait for a while
}
And check whether you have async attribute set while loading the .js files.

How to load a .js file 'locally'?

First of all: 'Locally' neither means "localhost", nor "local folder". It means a code area or a code space or a code region.
I have two JS (*.js) files for my site. One is to show a news ticker and other is to load something on hover. They are conflicting, and I can't remove any one of 'em because I need 'em.
So a thing comes up to my mind is: as I can make many things locally, why not I load a js file locally? Suppose:
<?php
if('condition') {
DO IT ONCE;
}
?>
<?php
if('other_condition') {
DO STH ELSE ONCE;
}
?>
In such case, the first condition doesn't bother the second condition. Even though the first one is doing, the second one is also doing well. No conflict, nothing.
If I can load a JS locally for a specific purpose and then break the JS loading further, then if I load other JS, she won't find any JS before, because that's for a specific purpose for the specific region only.
I think I'm clear with my idea. I'm here with a WordPress site, loading code specifically for home page using is_home() function. I want such a way to load a JS file for a region, and then break it to let the other JS function properly.
If you've designed your Javascript well, you can have two scripts that don't interfere. Without seeing the actual scripts, it's hard to recommend improvement. You could introduce new scopes for each of the scripts:
script1.js
(function() {
var script_variable = document.getElementById("my_form");
script_variable.onchange = function() { /* ... */ };
})();
script2.js
(function() {
// Same name!
var script_variable = document.getElementById("other_element");
script_variable.onclick = function() { /* ... */ };
});
Load each in a separate iframe.

How do I change the order in which Meteor loads Javascript files?

When you make a project with the Meteor framework, it packages all the files together, but there doesn't seem to be a way to explicitly say "I want this file to be loaded before that one".
Let's say, for example, I have 2 javascript files: foo.js and bar.js.
The file bar.js is actually containing code depending one the one inside foo.js but Meteor is loading bar.js before foo.js, breaking the project.
In node.js I would simply use require('./bar') inside foo.js
In the browser, I would put a <script> tag pointing to foo.js and another, after, pointing to bar.js, in order to load the files in the correct order.
How can we do that in Meteor?
According to the Meteor documentation, files are currently loaded in this order:
Files in [project_root]/lib are loaded first
Files are sorted by directory depth. Deeper files are loaded first.
Files are sorted in alphabetical order.
main.* files are loaded last.
Source:
http://docs.meteor.com/#structuringyourapp
Not a solution for all scenarios, but I think ideally anything that is dependent on other code would be placed in a Meteor.startup function, to ensure everything is already loaded.
You can always us a JS loader like yepnope.js and add it to the client.js file. This works for me.
I have a set of utility functions that I structured under common namespace (js global).
I.e.
// utils/utils.js
Utils = {};
and then in subfolders:
// utils/validation/validation.js
Utils.Validation = {};
// utils/validation/creditCard.js
Utils.Validation.creditCard = ... // validation logic etc
also I have bunch of code that uses Utils and it's subobjects.
Obviously, this structure doesn't work as Meteor load subfolders first.
To make it work as expected, I had to create /subfolder/subfolder/subfolder with meaningless names, and then shove root object in most deep subfolder, and branch objects in subfolders not so deep.
It is extremely counterintuitive for my taste and error-prone (suppose you have component that is even deeper in folder structure).
To address this issue, I used Q library with defers and promises. Solution still isn't clean as it makes you routine code repeating and checks but it gives you full control over the load order without messing with directory structure (hello to people who says you can organise meteor code as you want).
Example:
//utils.js
UtilsDefer = UtilsDefer || Q.defer();
UtilsDefer.resolve({
// here some root utils stuff
});
//cards.js
// here we'll depend on Utils but don't want to care about directory structure
UtilsDefer = UtilsDefer || Q.defer(); // it will be a) already
// resolved defer from utils.js, or b) new defer that will
// be resolved later in utils.js
UtilsDefer.then(function(Utils) {
// do something with utils usage, or for instance add some fields here
Utils.CreditCardDefer = Utils.CreditCardDefer || Q.defer();
Utils.CreditCardDefer.resolve({
// Credit card utils here
})
});
//someOtherFile.js
// it will be pain to use sub-objects with this method though:
UtilsDefer = UtilsDefer || Q.defer();
UtilsDefer.then(function(Utils) {
Utils.CreditCardDefer = Utils.CreditCardDefer || Q.defer();
Utils.CreditCardDefer.then(function(CreditCard) {
// do stuff with CreditCard _if_ you need to do it on startup stage
})
});
This is the example of rather narrow use case, as mostly you will be happy with handling these globals inside some user interaction callbacks or Meteor.startup where everything already initialised. Otherwise, if you want fine-grained control over initialisation order on very early stage, that could be a solution.

Categories