Let's say I have the following code:
let img = document.createElement("img");
img.addEventListener("load", function() {
alert("Loaded!");
});
img.src = external_string; // Can "load" fire here?
The question is - if the image in external_string
is already in browser cache, or maybe is base64 encoded, or whatever - can it so happen that the load
event is called immediately at the same line as src
is being assigned?
Note: I actually want it to be asynchronous because I want to set up a few more things before the load
event gets fired. But if there is a chance that it might get fired synchronously then I need to put in extra work to postpone that.
I could not find this subtlety explained in any document, but practical tests always call the event asynchronously.
CodePudding user response:
You can use the decode() method to wait for images to be ready. Even if the image loads immediately, queuing the promise micro-task will always ensure code runs after the promise resolves
Promise handlers
.then
/.catch
/.finally
are always asynchronous.Even when a Promise is immediately resolved, the code on the lines below
.then
/.catch
/.finally
will still execute before these handlers.
// Base64 data URI requires no loading time
const red_dot = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
const img = document.createElement("img");
img.src = red_dot;
img.decode().then(() => {
console.log("img ready, this will log second");
document.body.append(img);
});
console.log("img loading, this will log first");
Keep in mind that you cannot call decode()
before setting src
.
The load event will also always trigger and a listener can be added at any time however since it relies on the event loop, control over the order of operations is non-deterministic. That being said, any procedural code you add after setting the src
will always execute before the event handler fires.
// Base64 data URI requires no loading time
const red_dot = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
const img = document.createElement("img");
img.addEventListener("load", () => {
console.log("img ready, this will log second");
document.body.append(img);
});
img.src = red_dot;
console.log("img loading, this will log first");