2

I'm trying to figure out WHEN JavaScript is executed when one loads a HTML + JS content with .ajax() jQuery function and inserts the content with .html(content). I've read about domManip, read

And I've learnt a lot, but have not found out when the script is run:

  1. Will jQuery run the script after parsing and inserting the HTML? (So I can refer in JS every DOM object from loaded HTML)
  2. Will jQuery run the scripts in the order they are encountered? What happens when the script is to be loaded with src?

For example, this is a HTML loaded by .ajax() and then inserted with .html():

<p id="p1">Lorem ipsum...</p>
<script type="text/javascript" src="file.js">
<p id="p2">Dolorem...</p>

On my computer, on three browsers, in file.js I can refer to #p2 and everything works.

Community
  • 1
  • 1
jacek.ciach
  • 904
  • 11
  • 20

2 Answers2

2

Taking a look at the sources of jQuery 1.11.0 in uncompressed form, it's pretty clear that scripts will be detected by jQuery, and executed using eval().

Quoting from the domManip function:

// Evaluate executable scripts on first document insertion
for ( i = 0; i < hasScripts; i++ ) {
    [...]
    if ( node.src ) {
        // Optional AJAX dependency, but won't run scripts if not present
        if ( jQuery._evalUrl ) {
            jQuery._evalUrl( node.src );
        }
    } else {
        jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
    }
    [...]
}

So they will actually be executed in the order they are encountered. This is only for inline scripts though as you can see. Thus, in your example with file.js, the former part of my initial answer stands:

The reason you can refer to p2 is that after inserting that HTML snipped, the browser will make a second regular HTTP request to load the file. It's a race condition nevertheless, but a very save one, because the parsing of the second p will always be faster than loading another JavaScript file from the server.


Old and incorrect assumption below.

In my opionion, jquery will run none of your inserted jquery scripts. The browser will. Thus, they are executed in the order of insertion.

My reasoning is that the <script> tag is nothing but yet another DOM node to jquery. There is no reason for it to look for anything executable in there - that's the JavaScript parser's job (which is part of the browser).

UweB
  • 4,080
  • 2
  • 16
  • 28
  • In jQuery documentation: `By design, any jQuery constructor or method that accepts an HTML string — jQuery(), .append(), .after(), etc. — can potentially execute code.` And, i.e, in http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/ So I conclude, that actually jQuery runs the scripts. So: where is the truth? ;) – jacek.ciach Jul 24 '14 at 08:35
  • For jquery to be the executor of the code, it would need to include a fully fledged javascript parser, which it doesn't. Or use `eval()`, which would be redundant, because by simply inserting JavaScript code into the DOM, the browser will execute it. – UweB Jul 24 '14 at 08:37
  • So is there a mistake in the jQuery documentation? In part: `method that accepts an HTML string (...) can potentially execute code`? – jacek.ciach Jul 24 '14 at 08:53
  • Answer amended. `globalEval` will refer to the browser's `eval()`, if it is supported. – UweB Jul 24 '14 at 09:21
  • And will scripts be executed after/before insertion of HTML? (In other words: The quoting you have provided is after/before the code that inserts plain HTML?) – jacek.ciach Jul 24 '14 at 09:50
0

I have created two files:

js_test.html:

<!DOCTYPE html>
<html>
  <head>
  <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
  </head>
  <body>
    <div id="div1"></div>
    <p id="clickable">Click!</p>
    <script type="text/javascript">

    $(document).ready(function(){
      $("#clickable").click(function(){
        $.ajax("js_test_insert.html").done(function(content){
          $("#div1").html(content);
        });
      });
    });

  </script>
  </body>
</html>

And js_test_insert.html:

<script type="text/javascript">
alert("Before.");
$("#inserted p").css("background-color","yellow");
alert("Middle."); 

$(document).ready(function(){
  alert("Inserted ready!");
});

</script>
<div id="inserted">
<p>Hello, World!</p>
</div>
<script type="text/javascript">
alert("After.");

function test() {
  alert("It should not run");
}

</script>

I've tried it on FF 18.0, Chrome 36.0 and IE 11.0 (also using emulation of previous IEs) and:

  1. p#clickable is clicked.
  2. "Hello, World!" appears above "Click!".
  3. Alert "Before."
  4. "Hello, World!" becomes yellow.
  5. Alert "Middle."
  6. Alert "Inserted ready!" (I don't understand why .ready() is executed)
  7. Alert "After."

jQuery firstly inserts HTML, DOM is built, and then JS is executed (in order of appearance).

EDIT: Why .ready() is executed? Because the event is still ,,in efect'' (the document is ,,ready'' all the time, isn't it?) -- so adding a new handler of this event causes an immediate execution of the handler.

Solved.

jacek.ciach
  • 904
  • 11
  • 20