James Thorpe
James Thorpe

Reputation: 32212

Is there a specification of script execution order when using iframes?

It's fairly well known and understood that browsers will execute <script> elements in the order presented within the source of a page (barring defer and async etc). What I've not been able to establish is if there is a specification that guarantees an order across <iframe> elements also.

If my main page contains:

<html>
  <head>
    <script src="a.js"></script>
  </head>
  <body>
    <iframe src="inner.html" />
    <!-- ... -->
  </body>
</html>

With inner.html being:

<html>
  <head>
    <script src="b.js"></script>
  </head>
  <body>
    <!-- ... -->
  </body>
</html>

Is it defined in a specification that a.js will execute before b.js?

What if the main page looks like this:

<html>
  <head>
    <script src="a.js"></script>
  </head>
  <body>
    <iframe src="inner.html" />
    <!-- ... -->
    <script src="c.js"></script>
  </body>
</html>

What is the guaranteed order of execution here, if there is one? Say a.js takes a long time to load - it's guaranteed to still run before c.js. But what if inner.html and all it's resources (including b.js) have loaded before a.js - is there anything in the HTML spec that says b.js will not run before a.js? If it all loads normally in a timely manner, is it defined in a spec somewhere as to whether b.js should execute before or after c.js?

The best I've managed to find so far from the <iframe> spec is:

When a Document in an iframe is marked as completely loaded, the user agent must run the iframe load event steps in parallel.

However that seems to just say (when you dig into the "iframe load event steps") that the load event will be dispatched in and amongst other things running on the main page, but doesn't say when the inner page will be parsed and content loaded and (critically) when scripts are to be run within it.

Upvotes: 3

Views: 1354

Answers (2)

Louis
Louis

Reputation: 151491

The specification of the script element seems clear to me:

There are three possible modes that can be selected using these attributes. If the async attribute is present, then the script will be executed as soon as it is available, but without blocking further parsing of the page. If the async attribute is not present but the defer attribute is present, then the script is executed when the page has finished parsing. If neither attribute is present, then the script is fetched and executed immediately, before the user agent continues parsing the page.

(Emphasis added.)

You ask:

Say a.js takes a long time to load - it's guaranteed to still run before c.js. But what if inner.html and all it's resources (including b.js) have loaded before a.js - is there anything in the HTML spec that says b.js will not run before a.js?

Yes, the section I quoted above implies that b.js won't run before a.js. Per the specification, parsing will stop while a.js is fetched and executed. Processing of the iframe is not going to happen until after parsing resume, which means that b.js cannot run before a.js.

c.js could execute before b.js. There is no single neat paragraph that I can point at to justify this though. The explanation for this is spread throughout the specification. What happens is that the iframe triggers a navigation to the URL passed in the src. (In the spec this is expressed as "Navigate the element's child browsing context to url." Navigation is described here.) This navigation event will cause a fetch to happen. (Fetch is described here.) And fetches are executed in parallel by default. A script element with src also fetches some data but (without async or defer) it also stops the parsing while the fetching happens.

Upvotes: 3

Ramesh
Ramesh

Reputation: 1287

Talking specific to chrome, each of the frames loaded inside the browser use the same render process but they have different contexts. (please check CEF3 underlying framework).Considering this fact only single process is responsible for both iframe and mainframe execution and following code, I think i can safely say that main frame loads first and then subframes are loaded. (can check callbacks we get from CEF3 on CEF test apps to confirm this again). i.e. a.js and c.js are executed first and then b.js.

Parent HTML code:

<head>
<script type="text/javascript">
window.abc = "ramesh";
</script>
</head>
<body>

<iframe id="iframeId" src="testiframe.html">
</iframe>

<script type = "text/javascript">
for (i=0;i<10000;i++) 
{
    console.log("something");
}
var p = document.getElementById("iframeId");
console.log(p.contentWindow.testValue);
</script>
</body>

iframe code:

<script type="text/javascript">
window.testValue = "pqrs";
console.log("xyz");
</script>
<body>
</body>

iframe code should take far less time than the for loop I am printing. But this code always prints consoles from main frame first and if i try to access testValue from iframe's contentWindow, it says undefined (this is done to check its not about console log printing order and actual javascript execution order).

Hope this helps. Let me know if I missed any detail while coming to this conclusion.

Upvotes: -2

Related Questions