image.onload event and browser cache
As you're generating the image dynamically, set the onload
property before the src
.
var img = new Image();
img.onload = function () {
alert("image is loaded");
}
img.src = "img.jpg";
Fiddle - tested on latest Firefox and Chrome releases.
You can also use the answer in this post, which I adapted for a single dynamically generated image:
var img = new Image();
// 'load' event
$(img).on('load', function() {
alert("image is loaded");
});
img.src = "img.jpg";
Fiddle
OnLoad doesn't fire on cached images
Okay, this is not exactly what I asked for, but I found one thing that can help me - the completed
field
export const Picture: FC<PictureProps> = ({ src, imgCls, picCls, lazy, alt: initialAlt, onLoad, onClick, style }) => {
const alt = useMemo(() => initialAlt || generator.next().value, [src, initialAlt]);
const ref = useRef<HTMLImageElement>();
const onLoadTriggered = useRef(false);
const { publicRuntimeConfig } = getConfig();
const onLoadFunc = useCallback(() => {
!onLoadTriggered.current && onLoad?.();
onLoadTriggered.current = true;
}, [onLoad]);
useEffect(() => {
ref.current.complete && onLoadFunc();
}, []);
return (
<picture style={style} className={picCls}>
{!publicRuntimeConfig.dev && <source srcSet={`${src}.webp`} type="image/webp"/>}
<img onLoad={onLoadFunc} className={imgCls} alt={alt} src={src} loading={lazy ? 'lazy' : 'eager'}
ref={ref} onClick={onClick} />
</picture>
);
};
This code did solve my problems, but it seems like it's a crutch. So, I've decided to leave this solution here, but I'm still waiting for the correct answer
Javascript image onload fails on Firefox and Chrome
Yes, the load event does correspond to the time when the network resource has been fetched and when the browser has ensured it will be able to read it without issue.
That's when Firefox and Safari do fire the event, as per the specs.
Chrome currently does more work before firing this event, as they will wait until the full decoding is done.
So as you correctly guessed, Safari and Firefox will first render the <img>
element empty, apply the transition on that empty image and then only render the final image.
To overcome this issue you can use a relatively recent addition to the HTML specs: HTMLImageElement#decode(). This method will return a Promise, resolving when the decoding part has been completely done.
const imgElement = new Image();
const rootElement = document.getElementById("root");
rootElement.append(imgElement);
imgElement.className = "image";
imgElement.src = "https://picsum.photos/3000/3000";
imgElement.decode().then(()=>{
imgElement.classList.add("loaded");
});
.image {
border: 2px solid gray;
max-width: 100%;
opacity: 0;
transition: opacity 0.3s ease;
}
.image.loaded {
opacity: 1;
}
<div id="root"></div>
NextJS: Images loaded from cache don't trigger the onLoad event
I ended up using ImageObject.complete
as a workaround thanks to someone's suggestion.
I used useRef
to reference the image and checked if the image.current.complete === true
on component mount.
Here is the code:
import React, { useEffect, useRef, useState } from "react"
const Home = () => {
const [loaded, setLoaded] = useState(false)
const image = useRef()
const homeStyles = {
width: "100%",
height: "96vh",
backgroundColor: "black"
}
const imgStyles = {
width: "100%",
height: "100%",
objectFit: "cover",
opacity: loaded ? 1 : 0
}
const handleLoad = () => setLoaded(true)
useEffect(() => {
if (image.current.complete) setLoaded(true)
}, [])
return (
<div className="Home" style={homeStyles}>
<img alt="Sample Image"
ref={image}
onLoad={handleLoad}
src="https://images.unsplash.com/photo-1558981001-5864b3250a69?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
style={imgStyles}
/>
</div>
)
}
export default Home
Cross-browser image onload event handling
I'm not sure what browsers are affected, but it is easy to check for.
var img = new Image();
img.src = "foo.jpg";
if (img.complete || img.readyState === 4) {
// image is cached
doneCallback();
}
else {
$(img).on('load',doneCallback);
}
UPDATE
If you change the code around, it will consistently fire a load event in all browsers.
var img = new Image();
$(img).load(doneCallback);
img.src = "foo.jpg";
jQuery callback on image load (even when the image is cached)
If the src
is already set, then the event is firing in the cached case, before you even get the event handler bound. To fix this, you can loop through checking and triggering the event based off .complete
, like this:
$("img").one("load", function() {
// do stuff
}).each(function() {
if(this.complete) {
$(this).load(); // For jQuery < 3.0
// $(this).trigger('load'); // For jQuery >= 3.0
}
});
Note the change from .bind()
to .one()
so the event handler doesn't run twice.
image load event on IE
This is a very old bug that actually was fixed in all modern browsers except IE.
They didn't trigger onload event if image was obtained from cache.
But there is a workaround that is well-known by every person who tried to create an image gallery in javascript a couple of years ago:)
Image DOM element has a property .complete
that indicates whether image was loaded or not. You can check this property on script load. If image is in the cache img.complete will return true right after page loaded:
$('img').each(function(){
//this code will not run in IE if image is in the cache
$(this).on('load', function(){
checkImage(this);
});
//this code will run if image is already in the cache
if (this.complete) checkImage(this);
});
function checkImage(){
//your code for checking image
}
Related Topics
Disabling the Context Menu on Long Taps on Android
Capture Keys Typed on Android Virtual Keyboard Using JavaScript
Detect Double Tap on iPad or iPhone Screen Using JavaScript
Fcm - Programmatically Send Push Notification to User Segments
Declaring JavaScript Object Method in Constructor Function VS. in Prototype
How to Display All Methods of an Object
Chrome Extension Code VS Content Scripts VS Injected Scripts
Working Twitter-Typeahead Example
Ruby on Rails - Put Method on Update Ajax
React 'Cannot Read Property of Undefined' When Using Map
Fast Stable Sorting Algorithm Implementation in JavaScript
What Limitations Apply to Opaque Responses
Changing Iframe Src with JavaScript
Call Angularjs from Legacy Code
Why Does JavaScript Variable Declaration at Console Results in "Undefined" Being Printed
Why Is String "11" Less Than String "3"