Reputation: 32212
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
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 thescript
will be executed as soon as it is available, but without blocking further parsing of the page. If theasync
attribute is not present but thedefer
attribute is present, then thescript
is executed when the page has finished parsing. If neither attribute is present, then thescript
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 beforec.js
. But what ifinner.html
and all it's resources (includingb.js
) have loaded beforea.js
- is there anything in the HTML spec that saysb.js
will not run beforea.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
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