Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What exactly is innerHTML, and how does document.write work?

Consider the following:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="script.js"></script>
    <script type="text/javascript">
        document.write('<script type="text/javascript" src="script2.js"></scr'+'ipt>');
        document.write('<script type="text/javascript" src="script3.js"></scr'+'ipt>');
        console.log(document.getElementsByTagName("script").length + " Scripts");
        console.log(document.head.innerHTML);
    </script>
</head>
<body>
</body>
</html>

What would you expect the console.log to contain? I hope you come to one of the two outcomes that I would expect: 4 Scripts and either the two existing or all four script tags shown in the head's innerHTML (document.write could as well write to the body, so one could expect the script tags to be injected as children of the body).

The thing is that, in Chrome and IE11, the first script tag added via document.write is shown in the head's innerHTML, but the second isn't, and the DOM query result is 3 Scripts.

Could anyone please elaborate?

like image 707
Alexander Avatar asked Apr 10 '15 09:04

Alexander


2 Answers

Giving it a chance to render works in Chrome:

In the script I have script.js: x=1, script2.js: y=1 and script3.js:z=1

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="script.js"></script>
    <script type="text/javascript">
        console.log("after 1",x);
        document.write('<script type="text/javascript" src="script2.js"><\/script>');
        document.write('<script type="text/javascript" src="script3.js"><\/script>');
        setTimeout(function() {
          console.log(document.getElementsByTagName("script").length + " Scripts");
          console.log(document.head.innerHTML);
          console.log("after 3",x,y,z)
        },100); // the milliseconds MAY need to be higher over the net
    </script>
</head>
<body>
</body>

Result:

4 Scripts

<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
    document.write('<script type="text/javascript" src="script2.js"><\/script>');
    document.write('<script type="text/javascript" src="script3.js"><\/script>');
    setTimeout(function() {
      console.log(document.getElementsByTagName("script").length + " Scripts");
      console.log(document.head.innerHTML);
      console.log("after 3",x,y,z)
      },10)
</script><script type="text/javascript" src="script2.js"></script><script type="text/javascript" src="script3.js"></script>

after 3 1 1 1
like image 87
mplungjan Avatar answered Oct 12 '22 18:10

mplungjan


One possible explanation of the 3 count is that the scripts added via document.write are executed synchronously. So:

  1. Script engine executes the script block that contains document.write

    • Script engine adds the first script to DOM.
    • Script engine does not add the second script to DOM -- it must wait for the first script to download and execute. After all, it is possible for the first script to do a document.write("<!--");
    • Script engine returns the count 3
  2. Script engine downloads the first script and executes it.

  3. Script engine adds the second script to the DOM, downloads it and executes it.

Keep in mind that JavaScript is single threaded. This prevents the execution of script tags generated by document.write until the script that generates script tags is finished.

like image 23
Salman A Avatar answered Oct 12 '22 19:10

Salman A