I am looking for some help understanding something on a project I am working on. I have written some code that is functioning, though I am not sure why.
In a Node.js server, in /public/js there are two scripts. One (file1.js) has a function func(). file2.js, in the same directory, calls func() successfully. There is no module.exporting or requireing anywhere, yet the two files work together. They are both referenced in the index.ejs file, however. Is this where they become able to communicate?
//file1.js
function func() {
console.log("foo")
}
//file2.js
func()
//index.ejs
...
<script src="public/js/file1.js"></script>
<script src="public/js/file2.js"></script>
...
I've spent all day reading and cannot find anything on this topic.
Your question is about how JavaScript works in a browser.
Node.js isn't relevant here. All it is doing is running an HTTP server program that gives static files to the browser.
When you load a script into a browser using a script element (and don't use type="module"), any variable in the outer most scope of the script file (e.g. which isn't let inside a block or var inside a function) becomes a global and is accessible to any other script loaded into the same HTML document that way.
Globals are messy and a good way for different bits of code to accidentally interfere with each other so modern JavaScript generally avoids using them. This style of JavaScript programming wasn't common when JS was first implemented in browsers: Hence the behaviour described above.
This is why people started to use techniques like the revealing module pattern and why AMD and Node modules were designed before standard JavaScript modules were added to the specification.
You must understand how the global space behaves in Javascript.
This Code:
<script src="public/js/file1.js"></script>
<script src="public/js/file2.js"></script>
Is the same as this:
<script>
//file1.js
function func() {
console.log("foo");
}
func();
</script>
Because soon as file1.js is loaded, everything that is defined inside of it, becomes available anywhere in that page from where it was included.
Since file2.js uses contents of file1.js, it will work because func is available to be used anywhere below file1.js inclusion.
Related
I'm just getting started with JavaScript and have not seen a thread with my specific issue. A simple HTML file wants to execute a JavaScript file
<html>
<head>
<script type="text/javascript" src="/home/gewurztraminer/workspace/morpheme/site/index.js"></script>
<body>
<p>test</p>
</body>
</html>
and in the JavaScript file I have a simple function invoked after a variable called net is equal to the requiring of 'net' string for server-related purposes.
var net = require('net');
(function() {
alert("hi");
})();
The alert does not display in this case. But if I were to remove the first line so that only the function exists,
(function() {
alert("hi");
})();
everything works fine. Can someone give a detailed explanation so that this is easily accessible to other newbies? The answer to this question is not readily available online.
require is not a function provided by the JavaScript language or by browsers.
It is a function provided by Node.JS (which doesn't run inside a browser) and various module loading scripts (such as RequireJS).
Given that you are trying to load a module called net, it looks like you are trying to run code designed to run under Node.JS in an HTML document in a web browser … which won't work.
I have a function that I wrote to be included on all pages that will provide a CSRF token to all POST headers. Since I want it on all pages, I included it in my common.js file that is created by webpack and loaded in the head of the page.
function setupAjaxCsrfToken(){
var csrf_token = $('meta[name="csrf-token"]').attr('content');
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
if (options['type'].toLowerCase() === "post") {
jqXHR.setRequestHeader('X-CSRFToken', csrf_token);
}
});
}
I originally wanted this to be a IIFE but since my posts are in other files, I decided to just call it at the top of the js file where the posts are (Maybe it should work and it's the same issue as I'm about to describe). The file I'm calling this function from is loaded in the footer of the page, so that the other js file can load first. But when the function gets called, I get a function is not defined error. I've also tried this using a named function expression, with the same result (function is not defined). My original thought was that it might have been a race condition and that the function is not getting defined until after it is called, but I tried using let declaration and didn't see a change in the error output so I figured it wasn't getting hoisted. A little fuzzy on how function hoisting works so maybe I'm off there. My next thought is that webpack is closing off the scope, making functions within the common.js inaccessible to other files. How can you make functions in the main js file that is webpacked accessible to other filse?
Webpack does indeed isolate the execution environment of each module. All modules fed to Webpack will be placed in a function expression to allow Webpack to isolate each modules' code from other modules, and correctly handle the exports/imports that each module needs.
To solve your problem, you can set a property on window to expose a global variable. However, this will only work in a browser environment, due to window being a browser-specific global variable (Node and other execution environments may not support it).
The following code, if placed after the function declaration, will allow you to refer to the setupAjaxCsrfToken function by referencing window. setupAjaxCsrfToken.
The runtime race condition shouldn't be a problem, as browsers' generally execute javascript code sequentially.
window.setupAjaxCsrfToken = setupAjaxCsrfToken;
I am writing a HTML page that loads two js files. The two js files both use function a(), so I guess that if I can create the third js file and throw same function a() into that file, the browser might load faster because it doesn't have to load the same function twice. So can somebody tell me if I am on the right track about this, and how to load functions from different js file?
Thank you!
Long answer - all your code shares the same global scope.
So if you define a function a at the top-level scope of a file - there is no need to include a into each. There are exception, of course.
On the contrary - including it only once and only when needed would actually benefit you, in common case - since each of the consequitive files would be smaller, and as such require shorter time to download, thus making your site "faster".
There is some reading you might benefit from:
Scope:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions_and_function_scope
http://coding.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/
Relevant Module Pattern:
http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
Common implementation of an AMD spec:
http://addyosmani.com/writing-modular-js/
http://requirejs.org/docs/whyamd.html
So can somebody tell me if I am on the right track about this
You might be. If the function is absolutely enormous, it might improve performance (in terms of not having to download the function twice; the effect on execution time is negligible), but there are better reasons to split it out into a separate file:
You only have to change it once if you need to change it.
The browser can cache it separately.
As for loading it in browser JavaScript, just add another <script> element for it:
<script src="a.js"></script> <!-- Contains a() -->
<script src="b.js"></script> <!-- Uses a() -->
<script src="c.js"></script> <!-- Also uses a() -->
To accomplish what you are looking for, move function a() into its own file (3) and remove it from files 1 & 2. Then when referencing your javascript files inside your HTML, include this 3rd file first.
One caveat is that you want to make sure function a() is the exact same.
For optimal performance, you want to combine all of your JS into one file and then minify. A good place to start is using Chrome's Page Speed (F12 > Page Speed tab)
I would like to use requirejs to manage my code within a firefox xul plugin, and I can't get it to find my modules.
I know that xul doesn't play nice with the data-main attribute, so I have my main.js script as a second script:
<script src="chrome://myPackage/content/require.js" type="application/x-javascript"></script>
<script src="chrome://myPackage/content/main.js" type="application/x-javascript"></script>
This successfully calls the script, and the require function is available within main.js, but when I run
require(['lib1'], function(lib1){
alert(lib1.val1);
})
the alert never gets popped (lib1 is in the same directory as main.js).
I have tried this within and without setting the baseUrl as
require.config({
baseUrl: "chrome://myPackage/content/"
})
and it does not work either way.
Does anyone know how I can get require.js to look in the right place for my modules?
Addendum **
I added an error handling function and the error code returned is
http://requirejs.org/docs/errors.html#timeout
I have loaded the test module into a normal web page successfully. This seems to confirm that the issue is path configuration (it also takes the 15 second timeout before failing)
Firebug seems to have a working requirejs version. But more importantly, they have a far better mini-require.js that will not pollute the shared global scope when used in overlays (if used correctly :p)
https://github.com/firebug/firebug/blob/master/extension/modules/require.js
https://github.com/firebug/firebug/blob/master/extension/modules/mini-require.js
I suggest you have a look at these implementations and also the code using it.
Proactive warning:
Please note, that if your add-on uses code that defines lots of new properties on the scope in overlays (window) either by defining global functions or variables or implicitly declaring variables within functions, then this may interfere with other code running in the same scope (the browser code itself and other add-ons). Besides, should you want to submit your add-on to addons.mozilla.org, then a reviewer might not give it public status if your add-on "pollutes" the global scope/namespace in the main overlay.
I have a page javascript page.js being loaded with require.js. The call to the page.js is placed on the bottom of the page after the calls to require.js and is as follows:
<script>
require(["page"]);
</script>
Functions inside the page.js simply do not execute each time the page is accessed.
To be clear, an alert('hello'); in the middle of page.js will be alerted most but not all of the times. I'm pretty sure this is not an existing IE issue, and that a simple alert will always execute provided there are no other JS errors.
95% of the time the page and it's corresponding functions execute, about 5% of the time the IE browsers are not reexecuting the contents of the page.js.
I don't think this is an inherent IE issue, but rather require.js is stumbling over related aggressive caching issues found in IE.
Edits:
Just to clarify, the page.js file is visible in the f12 dom load when the error occurs. The page is properly cached. The issue is that the cached code file is not re run!
For instance the alert in this file is not executed!
I'm not sure about the internals of require.js but I suppose they do xhr for the resources and eval it. It seems the xhr completes and loads into the dom, but the eval isn't working correctly. (This is of course speculation, as I don't know enough require.js internals).
The only way i know to prevent caching your js files is to add a random string to the end :
example :
<script src="http://www.mydomaine.com/myjsfile.js?t=123456"></script>
generate the "t" parameter content randomly using an md5 hash or wathever, this makes browsers believe that it's a different file each time.
There problem may not be due to caching. Caching is basically controlled on the server-side, so if you do not want a file cached, you have the server setting the cache-control headers to do that. Caching does not affect if a javascript file is "executed" or not, it only affects where the browser gets data from when trying resolve a given resource. Normally, you want .js files to be cached for performance reasons.
In your case, caching may not be the real problem. When using dynamic javascript source loaders (libraries like dojo support this), it may best that the file you load is wrapped in the following:
(function(){
// Main code here...
})();
This defines an anonymous function, and then executes it right away. This gives the following advantages:
Creates a closure so you can declare variables that are only visible in the scope of your file.
Ensure that any direct executable statements are executed.
Note, I'm not familar with require.js, so there is a possibility it can play a role in your problem. Also, you did not provide the file you are loading via require, which it may have a bug that is causing the inconsistency you are encountering.
Conclusion:
IE (where it was mostly occurring) was kind of swallowing up the error, when we were able to reproduce it in Chrome, we found an error indicating that one of our global funcs wasn't yet loaded because the global funcs file wasn't added to the require list. Unfortunately, we're not using require.js's compile + optimization which may or may not have barfed without an IMPLICIT listing of the globals.js as a dependency.
I guess the take home is make sure any functions called are themselves defined in a dependency implicitly listed in the require block!