I've just begun to work with Require.JS and I'm a bit unclear on the appropriate cases in which it should be used, as well as the correct way to use it in those cases.
Here's how I currently have things set up with Require.JS. I have two functions, functionA() and functionB(). Both of these functions require an additional function, functionC() to work properly.
I only want to load functionC() when necessary, i.e. when functionA() or functionB() is going to be called. So I have the following files:
functionC.js
functionC(){
//do stuff
}
functionA.js
functionA(){
define(['functionC'],function(){
//functionC() is loaded because it is listed as a dependency, so we can proceed
//do some functionA() stuff
});
}
functionB.js
functionB(){
define(['functionC'],function(){
//functionC() is loaded because it is listed as a dependency, so we can proceed
//do some functionB() stuff
});
}
So, is this set up correctly? And if I end up calling both functionA() and functionB() on the same page, is extra work being done since they both load the functionC.js file? If so, is that a problem? And if so, is there a way to set it up so that they first check to see if functionC.js has been loaded yet, and only load it if it hasn't been? Finally, is this an appropriate use of Require.JS?
define() should only be used to define a module. For the above example, where a piece of code should be dynamically loaded, using require() is more appropriate:
functionA.js
functionA(){
require(['functionC'],function(functionC){
//use funcC in here to call functionC
});
}
Some notes:
require([]) is asynchronous, so if the caller of functionA is expecting a return value from that function, there will likely be errors. It is best if functionA accepts a callback that is called when functionA is done with its work.
The above code will call require() for every call to functionA; however, after the first call, there is no penalty taken to load functionC.js, it is only loaded once. The first time require() gets called, it will load functionC.js, but the rest of the time, RequireJS knows it is already loaded, so it will call the function(functionC){} function without requesting functionC.js again.
You can find details about RequireJS and JavaScript modularity here: JavaScript modularity with RequireJS (from spaghetti code to ravioli code)
Related
In a script associated with an Orchard view I try to post an AJAX to server with dojo.request.post function. However, I only get esri/request, dojo/request is undefined. I call the request outside the function where the require statements reside, but there's no problem with other required packages as long as I use them in correct format. Dojo/request works in our other project, so I suspect Orchard of messing things up (the other project's dojo/request use is in a plain page, not in a view), though I would expect problems caused by it to surface earlier.
Important parts of the code:
require([ ... "dojo/request", ... ], function (... Request, ...) {
//custom init function contents
})
function sendResults(featureSet) {
//custom code processing the parameter, making uri, JSON and like
dojo.request.post(uri, {
//sending data
})
}
My razor require part in the same file contains:
Script.Require("esri/JavaScriptApi").AtHead();
Script.Require("dojo").AtHead();
Those are defined in resourcemanifest.cs:
manifest.DefineScript("esri/JavaScriptApi").SetUrl("http://js.arcgis.com/3.14/");
manifest.DefineScript("dojo").SetUrl("//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js");
The error I get when I try to run the code:
TypeError: dojo.request is undefined
I've tested it in FireBug and confirmed that dojo/request doesn't exist (the same for variants, like dojo/Request), only esri/request is a function, but it has no post method.
I'm stuck here. Google search lead to "plains of sheer desperation" (page 5+) with no useful output and my co-workers don't know. Does anyone know why I can't see dojo/request and how to get it?
As far as I'm aware, dojo/request does not export a global (as modern AMD modules generally shouldn't need to), so dojo.request would never work in any context.
The appropriate way to use AMD modules is to use them within the body of a require callback (or, even better, organize your own code in AMD modules as well, and use them within a define factory function).
require([ ... "dojo/request", ... ], function (... request, ...) {
request.post(...);
})
Alternately, if you're certain dojo/request has been loaded by the time you want to use it, you could use single-argument require to reference it:
require('dojo/request').post(...);
However, this is typically not ideal and seen as a hack.
Perhaps the Introduction to AMD Modules tutorial would help to better understand optimal AMD usage.
requireJS is giving me a headache atm. requireJS is AMD which by definition says it's asynchronous. Normally I would define a module like this.
define("some Name", ["./moduleOne"],function(moduleOne){
//this would be undefined
moduleOne.whatEver();
var aMethod = function(){
//user aModule.whatever();
}
return {
method: aMethod;
}
});
Ok, I got that I can't directly use moduelOne.whatever because it is loaded asynchronous and it's not there if the callback is being called.
First Question, is this correct?
Now if I change the module definition to this:
define("some Name", function(require, exports){
var moduleOne = require(".moduleOne");
//this is OK
moduleOne.whatEver();
var aMethod = function(){
//user aModule.whatever();
}
exports.method = aMethod;
});
I can use aModule.whatever directly. As I read from the docs, using this (commonJS) style, requires parses the function with Function.prototype.toString, sees the require statement and load the modules directly.
I am pretty sure, I am misunderstanding something here and it would be nice of someone could explain how exactly requireJS works and if the second style is really synchronous.
Thanks
You've misunderstood how it works.
In both examples you give in your question the sequence of execution is:
Something requires the module named some_Name. (I don't think RequireJS is happy with module names that have spaces so I'm assuming a module name with an underscore.)
RequireJS looks for the dependencies and the factory function for the module some_Name. The factory is the function given to define when you define the module.
a. If it happens that define("some_Name"... was called before this step, then RequireJS just gets the dependencies and factory function that was given to define.
b. If define("some_Name"... has not been executed yet, RequireJS will go to the network and attempt to fetch a file that contains the define call and execute it. By convention this will be a file with the same name as the module name + the .js extension, but this can be overridden in RequireJS' configuration.
RequireJS checks whether the dependencies are loaded. If not, then it issues require calls for each dependency that is not loaded yet.
RequireJS calls the factory function with the resolved dependencies.
Note that I did not go over all possible scenarios here. I'm sticking with the most common cases to keep things simple.
So...
Ok, I got that I can't directly use moduelOne.whatever because it is loaded asynchronous and it's not there if the callback is being called.
First Question, is this correct?
No, this is not correct. By the time moduleOne.whatEver(); executes, the module moduleOne must have been loaded already. If moduleOne is undefined this is not because of RequireJS' asynchronous nature but because there is a bug in how moduleOne is defined. For instance, if it exports the value undefined, then moduleOne will be undefined. Or you may get an undefined value for moduleOne.whatEver which will then cause an error when you try to call it, but this would be caused by, for instance, forgetting to export whatEver.
The difference between the 2nd case and the first is that the 2nd uses the CommonJS sugar syntax and this causes step 2 above to have a bit of additional processing. Before RequireJS executes the factory it parses the function (as you mentioned) and then processes the factory function as if the defined had been called like this:
define("some_Name", ['require', 'exports', './moduleOne'], function (require, exports) {
The require and exports modules are special modules defined internally by RequireJS. Note how RequireJS adds ./moduleOne at the end of the list of dependencies. Once this is done, the process is exactly the same as for the 1st case.
By the time var moduleOne = require("./moduleOne"); is executed, the module has already been loaded. So what this line does is merely return a reference to the module.
This code is from http://twitter.github.com/
(function ($, undefined) {
// more code ...
$.getJSON("https://api.github.com/orgs/twitter/members?callback=?", function (result) {
var members = result.data;
$(function () {
$("#num-members").text(members.length);
});
});
// more code ...
})(jQuery);
First, things I understand:
All the code is wrapped in a IIFE
They are using Github API for getting the members
The URL includes the string '?callback=?' so the request is treated as JSONP.
What I don't understand is: why they are using $(function() ... inside the function that is executed if the request succeeds.
Is this code equivalent?
$(function() {
$.getJSON("https://api.github.com/orgs/twitter/members?callback=?", function (result) {
var members = result.data;
$("#num-members").text(members.length);
});
});
Maybe I'm wrong but what I think is that the second code snippet waits for the document to be loaded and then request the members ... so there is not parallelism? In the first code snippet the request is done in parallel with the document loading. Please correct me if I'm wrong.
The $ function, if it is passed a function as its argument (it is a horribly overloaded function), will call that function when the DOM is ready.
Having it there stops the code inside (which tries to modify the DOM) from running before the DOM is complete.
If the DOM is already complete before $ is called, then the function will be called immediately.
Note that the HTTP request sent by getJSON might get a response before or after the browser has finished loading and parsing the DOM of the original document.
This allows the request for the data to be sent without waiting for the DOM to be ready while still protecting against premature modification.
Is this code equivalent?
No. That waits for the DOM to be ready before it even sends the request for the data.
Maybe I'm wrong but what I think is that the second code snippet waits for the document to be loaded and then request the members
You're not wrong. That is exactly what happens. The first snippet is most likely used so the JSONP request can be made/returned while waiting for the DOM to be ready. They are just making the best use of the time available.
The chances are the DOM will be ready by the time the AJAX request is complete, but to be on the safe side there is no harm wrapping it in a ready event handler (if the DOM is already ready, jQuery executes the callback immediately).
As you know, this library makes use of jQuery. Now, I know how much we all love jQuery, but what if I want to use another library, such as MooTools or Prototype, that redefines the $ character we all know and love? Using the second example you gave, it breaks the code, because the author is trying to use properties of the $ that likely no longer exist because $ != jQuery.
But in the Twitter snippet, $ is a local variable, an argument to the IIFE, and the jQuery object, which is far less likely to be overwritten, is passed in as that argument. So now, anyone wishing to use this function/library can go ahead and use it without fear that it will break if they combine it with another library using the $.
In summary, It's all about namespacing, to prevent another library overwriting the $ and breaking your function definition.
I am using RequireJS and need to initialize something on DOM ready. Now, RequireJS provides the domReady plugin, but we already have jQuery's $(document).ready(), which is available to me since I have required jQuery.
So I have got two options:
Use the domReady plugin:
require(['domReady'], function (domReady) {
domReady(function () {
// Do my stuff here...
});
});
Use $(document).ready():
$(document).ready(function() {
// Do my stuff here...
});
Which one should I choose, and why?
Both the options seems to work as expected. I am not confident in the jQuery's one because RequireJS is doing its magic; that is, since RequireJS will dynamically add scripts, I'm worried that DOM ready may occur before all of the dynamically-requested scripts are loaded. Whereas, RequireJS will add a burden on additional JS just for domReady when I already have jQuery required.
Questions
Why does RequireJS provide a domReady plugin when we can have jQuery's $(document).ready();? I don't see any advantage of including another dependency.
If its just to feed a need, then why not provide one for cross-browser AJAX?
As far as I know, a module that requires domReady won't be fetched or executed after the document is ready, and you could do the same requiring jQuery as well:
require(['jQuery'], function ($) {
$(document).ready(function () {
// Do my stuff here...
});
});
To be more clear on my question: what's the difference between requiring domReady or jQuery?
It seems like all the key points were already hit, but a few details fell through the cracks. Mainly:
domReady
It is both a plugin and a module. If you include it in the the requirements array w/ a trailing ! your module won't execute until it's "safe" to interact w/ the DOM:
define(['domReady!'], function () {
console.info('The DOM is ready before I happen');
});
Note that loading and executing are different; you want all your files to load as soon as possible, it's the execution of the contents that is time sensitive.
If you omit the !, then it's just a normal module that happens to be a function, which can take a callback that won't execute before the DOM is safe to interact with:
define(['domReady'], function (domReady) {
domReady(function () {
console.info('The DOM is ready before I happen');
});
console.info('The DOM might not be ready before I happen');
});
Advantage when using domReady as a plugin
Code that depends on a module that in turn depends on domReady! has a very significant advantage: It does not need to wait for the DOM to be ready!
Say that we have a block of code, A, that depends on a module, B, that depends on domReady!. Module B will not finish loading before the DOM is ready. In turn, A will not run before B has loaded.
If you were to use domReady as a regular module in B, it would also be necessary for A to depend on domReady, as well as wrapping its code inside a domReady() function call.
Furthermore, this means that domReady! enjoys that same advantage over $(document).ready().
Re the differences between domReady and $(document).ready()
Both sniff out whether/when the DOM is ready in essentially the same way.
Re fear of jQuery firing at the wrong time
jQuery will fire any ready callback even if the DOM loads before jQuery does (your code shouldn't care which happens first.).
An attempt at answering your main question:
Why does requirejs provides a domReady plugin when we can have jquery's $(document).ready();?
They do two different things, really. RequireJS' domReady dependency signifies that this module requires the DOM to be completely loaded before it can be run (and can therefore be found in any number of modules in your application if you so desire), while $(document).ready() instead fires off its callback functions when the DOM is done loading.
The difference may seem subtle, but think of this: I have a module that needs to be coupled to the DOM in some way, so I can either depend on domReady and couple it at module definition time, or put down a $(document).ready() at the end of it with a callback to an init function for the module. I'd call the first approach cleaner.
Meanwhile, if I have an event that needs to happen right as the DOM is ready, the $(document).ready() event would be the go-to, since that does not in particular depend on RequireJS being done loading modules, provided the dependencies of the code you're calling it from are met.
It's also worth considering that you do not necessarily use RequireJS with jQuery. Any library module that needs DOM access (but does not rely on jQuery) would then still be useful by using domReady.
Answering your bullets in order of appearance:
They both do accomplish the same thing
If you have reservations about jquery for whatever reason then use domReady
Correct, so just use jQuery
Because not everyone uses jQuery
I agree, just use jQuery
Plugins by definition 'feed a need'.
Cross Browser ajax isn't a thing. Cross Domain? There probably is, and if there isn't then there is no need to feed.
, -, -, - Ok
When it comes down to it, you are overthinking this. It's a mechanism to execute javascript on domReady. If you didn't have jQuery I would advocate the domReady plugin. Since you have jQuery then don't load more scripts to do something that is already available.
Clarity Update
The domReady plugin collects functions to call when the document is 'ready'. If it is already loaded then they execute immediately.
JQuery collects functions and binds a deferred object to the dom being 'ready'. When the dom is ready the deferred object will be resolved and the functions will fire. If the dom is already 'ready' then the deferred will already be resolved so the function will execute immediately.
This means that effectively they do exactly the same thing.
After some experimenting with requirejs with multiple modules I suggest using domReady.
I noticed that function associated with $(document).ready(...) is not called when multiple modules are loaded by requirejs. I suspect that dom is getting ready before all requirejs code is executed and jquery ready callback handler is called before it gets bound with user defined function i.e. within main module code.
require(['jquery',
'underscore',
'text!some_template.html',
'./my_module_1',
'./my_module_2',
'domReady',
'other_dependency_1',
'other_dependency_2'
], function($, _, someTemplate, myModule1, myModule2, domReady) {
$(document).ready(function() {
console.info('This might never be executed.');
console.info('Dom might get ready before requirejs would load modules.');
});
domReady(function () {
console.info('This runs when the dom gets ready and modules are loaded.');
});
});
I found I do this as part of the main entry so that all of my javascript is guaranteed that the DOM is ready and jquery is loaded. Not sure how great this is so welcome any feedback but here's my main.js:
require(['domReady!'], function(domReady){
console.log('dom is ready');
require(['jquery', 'bootstrap'], function(){
console.log('jquery loaded');
require(['app'], function(app){
console.log('app loaded');
});
});
});
I'd love to live in a lint free world. JSLint that is. But I'm having some problems that I'm not sure I should ignore or fix. Specifically I'm getting a number of:
[functionName] not defined
errors. I do recognise that you should always define the function before using it and I assume that's what the message is really warning against but here are two cases where I think there is a valid exception:
jQuery(document).ready(function($) {
// code goes here
}
In a simple file which starts with a typical noconflict wrapper for jQuery I get a warning saying that "jQuery(document).ready(function($) {" is not defined. Obviously jQuery is defined in a separate file that needs to stay separate. Does that make sense?
The second example is really quite similar although arguably it is more avoidable. In this case I have two JS files in my project. One that looks just like the one above (aka, it's a set of DOM triggered events wrapped inside of jQuery's "ready" event). The other has a number of helper functions that look like this:
function doSomethingImportant() { };
function doSomethingImpressive() { };
These functions are then called within the first JS file. JSLint doesn't like this and complains every time the first JS file calls a function defined in the second JS file: doSomethingImportant() { is not defined. Yet in reality, since the functions are defined at load time and the calls to those functions always happen afterward based on DOM events there never seems to be a real problem.
Anyway, open to ideas. Is this a case of filtering JSLint's advice or something I should fix in code?
You're getting these errors because JSLint assumes that at some point in the future you might do:
var doSomethingImpressive = function() { }
in which case you would get an error, because the file where the function is defined is included after the function call (as explained here)
The same goes for the jQuery call. You can either change the order of your scripts, or safely ignore the errors.