Reputation: 591
When I try to learn Promise from developers.google.com I found there is a code like this.
<img id="img1" src="images1.jpg">
<script>
var img1 = document.querySelector("#img1");
img1.addEventListener("load", function(){
alert("yes");
});
img1.addEventListener("error", function(){
alert("no");
});
</script>
This code is not exactly the same with the one on google page, but should be function the same.
When I saw this I am curious as the script tag is at the very bottom of the page, "it should load the img first then load the js file so after the js file works it could not detect whether the img is loaded or not" I suppose, so I simulate this code in my editor, it turns out it works.
I try to search in google and found that it is surely HTML load from top to bottom, maybe not the same in some new browsers, then I open dev tool in chrome and try to learn sth from the networking, it is also the sequence it should be, which is, html, image file, js.
I need help, I do not understand, am I missing some basic loading knowledge here? or "load" listener doesn't work as I imagine?
Thank you.
Upvotes: 0
Views: 49
Reputation: 5244
Well, that requires some insight in how a browser reads in a HTML document and displays it to the user. Here is your code, but slightly expanded
<p>start page</p>
<img id="img1" src="images1.jpg">
<script>
var img1 = document.querySelector("#img1");
img1.addEventListener("load", function(){
alert("yes");
});
img1.addEventListener("error", function(){
alert("no");
});
</script>
<p>end page</p>
I try to search in google and found that it is surely HTML load from top to bottom
Yes, it reads in the above content in the top to bottom order. The incoming stream is being parsed as the order it comes in. So the first paragraph with text start page
is read first, then the image, then the script and then the last paragraph. If an element contains child elements, these get read from top to bottom too until the next element is being read.
But when it reads an element, such as <img>
, it initiates a new request to retrieve the image, defined in the src
attribute. That's done in a separate task.
After the image element, it finds a <script>
tag. Here, its content is then send to the browser's VM to run the script code. The VM executes the code step by step. In your script, you have instructed to
1. find the img1 element
2. listen to its "load" event
3. listen to its "error" event.
Yet, this is done so fast that the browser is able to parse the script before the image is being loaded. Step 1 always succeeds because the element is present and the script is running after. If you place the image element after the script, it would fail.
When step 2 succeeds depends of the size of the image file, network, the document's content, when the script is being handled ect ... If you wrap that code in a function and use setTimeout()
with an elapse time, then the alert wouldn't show up because the image file is already displayed before those event listeners are being hooked. Here below are two interactive examples with timeouts:
<p>start page</p>
<img id="img1" src="images1.jpg">
<script>
console.log('without timeout');
function f() {
console.log('alert?');
var img1 = document.querySelector("#img1");
img1.addEventListener("load", function() {
console.log("yes");
});
img1.addEventListener("error", function() {
console.log("no");
});
}
f();
</script>
<p>end page</p>
<p>start page</p>
<img id="img1" src="images1.jpg">
<script>
console.log('with timeout');
function f() {
console.log('alert?');
var img1 = document.querySelector("#img1");
img1.addEventListener("load", function() {
console.log("yes");
});
img1.addEventListener("error", function() {
console.log("no");
});
}
window.setTimeout(f, 1000);
</script>
<p>end page</p>
Upvotes: 2
Reputation: 2583
Browsers load images asynchronously. Here are the steps the browser will execute with your example:
img
tag and fire the HTTP request to get the image;script
tag and register all the defined eventHandlers;load
event;Upvotes: 1