16

I am having a error if I used async in script tag like below

<script async src="main.js"></script>

The error shows only on chrome saying

Uncaught ReferenceError: $ is not defined

If I removed the async from the script tag there is no more error in my console and everything works fine.

Do you have any idea why am having this problem ?

EDIT

Below script are placed inside the head tag

<!-- JS -->
<script async src="../js/jquery/jquery-1.10.1.min.js">    </script>
<script async src="../js/vendor/modernizr-2.8.2.min.js"></script>

<script async src="../js/asynchronous-resources/2014-06-03-asynchronous-resources.js"></script>

<!-- IE JS -->
<!--[if !IE]><!--><script async src="../js/ie10.js"></script><!--<![endif]-->

main.js is added to the footer.

<script async src="../js/main.js"></script>

I have found a similar question on stackoverflow. Load jquery asynchronously before other scripts

I had to change async to defer there is no more issue now in firefox, chrome and IE9.

Byt it breaks in IE8 and IE7 completely. jQuery stopped working if I use defer.

Community
  • 1
  • 1
Santosh
  • 3,477
  • 5
  • 37
  • 75

7 Answers7

28

Okay..... So Basically...

WITHOUT ASYNC:

JS files are downloaded and executed sequentially IN ORDER ... i.e., The first encountered JS file gets downloaded and executed first, then the next and so on, while at this time the HTML parser is blocked which means no further progress in HTML rendering.

WITH ASYNC:

JS files[all] are put to asynchronous download as they are encountered, and are executed as soon as they get fully downloaded. HTML parser is not blocked for the time they are downloaded. So the HTML rendering is more progressive.

DISADVANTAGE:

However, the problem with asynchronous download and execution is that the JS files are executed as soon as they are downloaded... i.e., NO ORDER is maintained..for example, a smaller JS file(main.js) that gets downloaded before a larger file(jQuery.js) gets executed before the larger file. So, if my smaller file has reference to some variable / code ($ of jQuery) initialized in the larger file, alas, the code has not been initialized yet and therefore an error is thrown. And that is what is happening here.

WHAT SHOULD YOU DO:

1> Remove async attribute and live with a lower performance.
2> Use dynamic loading of scripts which maintains the order of execution. Dynamic scripts are downloaded asynchronously by default but are executed seperately from the DOM parsing, therefore not blocking the HTML rendering. In this, by writing

script.async = false; 

we force these to get downloaded and executed IN ORDER.

<script type="text/javascript">
[
  'jQuery.js',
  'main.js'
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  script.async = false; 
  document.head.appendChild(script);
});
</script>
Community
  • 1
  • 1
Vaibhav
  • 575
  • 6
  • 5
4

Had the same problem but wanted to keep the async for better performance. I've fixed the problem by moving all code from main.js into an onload function. Like so:

window.onload = function () {

// main.js code

};

This way the main.js code only runs after the page is loaded (including the jQuery).

UPDATE: Here's another (better?) way:

var myScript = document.createElement('script');
myScript.src = 'http://code.jquery.com/jquery-1.9.1.min.js';
myScript.onload = function() {
  console.log('jQuery loaded.');
};

document.body.appendChild(myScript);
nunoarruda
  • 2,679
  • 5
  • 26
  • 50
2

Your main.js is getting executed asynchronously even before jquery is loading synchronously.

Either add async attribute to jquery as well or remove async attribute from main.js

MDN

Set this Boolean attribute to indicate that the browser should, if possible, execute the script asynchronously. It has no effect on inline scripts (i.e., scripts that don't have the src attribute).

Amit Joki
  • 58,320
  • 7
  • 77
  • 95
2

I just finished writing jsinit.js just for this purpose.

It enables you to use async even with jQuery. It works by delaying execution of your module until jquery has finished loading. (And it can be loaded "async" by itself!)

Have a look: https://github.com/ScheintodX/jqinit.js

Scheintod
  • 7,953
  • 9
  • 42
  • 61
2

This way work fine on ggle chrome for me : Replace

<script async src="JS/jquery-3.1.1.min.js"></script>
<script async src="JS/my.js"></script>

by

<script defer src="JS/jquery-3.1.1.min.js"></script>
<script defer src="JS/my.js"></script>

it charge first jquery and after my.js like the order

1

My guess is main.js has some jQuery in it. The async tag will force the browser to parse the JavaScript as soon as it is available, which may be before the jQuery script is ready.

From W3schools:

When present, it specifies that the script will be executed asynchronously as soon as it is available.

To solve:

  • Add the async attribute to your jQuery in addition to main.js
  • Remove the async attribute from main.js
  • Remove the async tag altogether

If you provide some more information on what you're using the async tag for I can offer some more suggestions.

Luke Peterson
  • 8,584
  • 8
  • 45
  • 46
  • 1
    Yes you are right main.js has jquery inside it. Is it not a good idea with jquery. – Santosh Jun 15 '14 at 08:55
  • Actually not. With jquery and main.js I am not able to use async. I found a similar question on stack which is resolved. I have updated on my question. – Santosh Jun 16 '14 at 02:21
1

To solve this problem you can simply write all of the inline code as a function. Then add the onload attribute to the script tag for the async jQuery like so:

 <script src="../scripts/jquery.min.js" async onload="myFunction()"></script>

Make sure that in the head section of your html myFunction is placed before the async script tag.

Headache
  • 239
  • 2
  • 8