Image.Onload Event and Browser Cache

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



Leave a reply



Submit