I'm looking for a reliable way to block image network requests with javascript. I read this: Prevent images from loading
It seems that it's a bit hit-and-miss as to whether the image request or the javascript will fire first.
Does anybody understand the order in which stuff happens? Can I tie into some sort of hook where I can run some javascript before any network requests are made? Or at least abort any existing ones.
Thanks.
Images are loaded when the src attribute is set. You can either dynamically create the image tags, or just set the src attribute when you want the image to load.
Also note that different browsers render pages in different ways. so preventing the load with javascript, is likely to work on certain browsers and not others
You can't avoid that - your browser will always try to load the images of your img tags. You will have to load the images dynamically via JavaScript.
Related
There are several Stack Overflow questions like How can I check if a background image is loaded? which are similar to mine. They attempt to run code when an element's background-image loads, and accomplish this by adding an onload handler to the element.
But what if you are running (for instance) a Puppeteer script, which checks the page after it has already loaded? In that case you can't add onload handlers.
Is there any way to verify that the background-image of an element loaded, "after the fact", without using onload?
The only way I can think of is to grab their background-image style, then fetch the image myself to see if it loads ... but that seems a lot slower than just asking the browser (somehow) if the image loaded ... especially if I'm checking a lot of background-images.
Puppeteer has a config for pages to check the number of idle connections. So the images should be loaded while there are no more requests than specified in 500ms.
await page.goto('https://www.google.com/', {"waitUntil" : "networkidle0"});
In the onLoad event, write away the data you wish to check such that you save state.
Then when your Puppeteer script runs, you will be able to re-inspect the very same data.
Is it possible to detect - using jQuery or pure DOM manipulation / events - when an image that was injected into the document has fully loaded? For example, a script needs to replace one image with another. If it just changes the src attribute, the user will see an image disappear briefly (or not so briefly, depending on their connection). So, a better option would be to create a new image element in some hidden place (or, if cross-platformly possible, out of DOM entirely) and switch images only when the new one is ready. Can this be done?
EDIT: It might be a separate question, but still... Is there also a way to detect when an image has failed to load?
You can use image.onload = function(){<...>};
Image is the actual image you want to get the load of.
<img src='...' id='image'>
In order to check if the image finished loading do the following->
document.getElementById('image').onload = function(){<...>}
or
document.getElementById('image').addEventListener('load',function(){<...>},false);
If you want to check if the image failed to load do this->
document.getElementById('image').onerror = function(){<...>}
or
document.getElementById('image').addEventListener('error',function(){<...>},false);
Note
.addEventListener method won't work in IE8. If you are planning on supporting it I can edit my answer.
yes you can do that by using the .load() event.
like,
$('#img1').load(function(){ alert('loaded'); });
the alert will be displayed when the resources for that particular selector has loaded fully.
The .load() event does not always work as expected and is prone to fail under different circumstances. For broadest browser support I suggest to use DeSandro's imagesLoaded (which I find to be best practice anyway): https://github.com/desandro/imagesloaded
My web page include a lot of img tags, but when it is initially displayed, most of the imgs are hidden. I want to load the imgs only when user shows the intention to view them, otherwise the page could generate too much network traffic.
I know I could insert the img tags into the DOM on the fly with javascript. But that way I lose the benefit of search engine indexing these images, I want the search engine bots to see these imgs.
Is there a way to keep the DOM structure unchanged, while loading the imgs only when needed?
You could try lazy loading:
Lazy Load delays loading of images in long web pages. Images outside of viewport are not loaded until user scrolls to them. This is opposite of image preloading.
demo: http://www.appelsiini.net/projects/lazyload/enabled_timeout.html
http://www.appelsiini.net/projects/lazyload
https://github.com/tuupola/jquery_lazyload
http://luis-almeida.github.io/unveil/
What you could do, is put all the images in a <noscript> tag, so browsers without JavaScript, and thus search engines, can see them.
You can then add the images in using JavaScript manually, for those who do have it.
Here's the code:
<div id="wrapper">
<img src="lowres/image123.jpg">
</div>
PREMISSES:
The <img> element is generated by a proprietary system backend and uses a low resolution image as source. I can only operate on it using pure javascript (no jquery!).
I NEED TO change de src attribute to a high resolution version located in a external server, eg.: src="//cdn.provider.com/highres/image123.png" (images have the same name but different locations).
THE PROBLEM: doing it after <img> insertion into DOM issues 2 (two) HTTP requests, one for the lowres image and other for the highres - and I have lots of images on the page!
In order to FIX IT, I was wondering if it is possible to manipulate <img> just before its insertion into DOM to change src appropriately, for example by intercepting an <img> event "beforeInsertion" or an event "afterInsertion" of the <div> wrapping it.
Cheers!
UPDATE 1: to make things clear: 1) I don't have accesss to the backend/server side; 2) I don't want to display the low resolution image, just the high resolution; 3) I dont' know the file name in advance, I need to get it from the <img> and append it to the path of the high resolution version stored in the CDN (both images have the same name); and 4) I can do it with the code bellow, but at the cost of TWO HTTP requests, which is what I want to avoid and what has motivated this question! ;)
var img = document.getElementById("wrapper").childNodes[0];
img.src = getHighResolutionImagePath(img.src);
You have to change url before adding <img> tag to document (e.g in server side script). Browser will get image from given url as soon as it'll receive tag, so it's not possible to replace it then. Especially that js will execute after getting all elements used on website.
When you're developing an app for retina displays and you want to let the browser know it's a high resolution image, you would append "#2x" to the picture name, like so:
background-image: url('../img/logo2#2x.png');
Try that and see if the browser adopts the same policy.
Source: http://benfrain.com/how-to-serve-high-resolution-website-images-for-retina-displays-new-ipadiphone4/
You must listen to mutation events, specifically DOMNodeInserted
Full documentation is available at MDN > Mutation Events
Once you have detected that an image as been added (you must filter the proper image type) you can replace the source for the one you want.
A small snippet taken from MDN:
element.addEventListener("DOMNodeInserted", function (ev) {
// ...
}, false);
Beware that performance will be greatly degraded
So there's no issue with this code functionality itself. I have something like this:
<div>
<div><img id="imageToChange" src="/path/image.png" /></div>
<div id="textToChange">Text</div>
</div>
I have another part of my code, that changes the image src/text with jQuery.
function changeImage() {
$('#imageToChange').prop('src', '/path/image2.png');
$('#textToChange').html('New Text');
}
As you may expect, this works exactly as I expect it to. But with 1 quirk.
In all the main browsers (chrome/FF/IE). The image takes a long time to change.
So for example, when I call changeImage(), the text will change instantly, but the image may not change until 1-2 seconds later. (Not large images by any stretch, about ~6KB, and local)
I haven't found anyone else really complaining about it, but what I'm wondering is if there's any way to speed up the changing of the image src? Perhaps a better way to do it?
This is jquery 1.8.0 as well.
Thanks
I have seen this behavior before. The delay is caused by the image not being cached and the subsequent load time. The only solutions I know of:
Preload your images with JavaScript Image objects.
Handle the load event on the image and update the text after the image as loaded. Note jQuery lists some issues to watch out for:
Caveats of the load event when used with images
A common challenge developers attempt to solve using the .load()
shortcut is to execute a function when an image (or collection of
images) have completely loaded. There are several known caveats with
this that should be noted. These are:
It doesn't work consistently nor reliably cross-browser
It doesn't fire correctly in WebKit if the image src is set to the same src as before
It doesn't correctly bubble up the DOM tree
Can cease to fire for images that already live in the browser's cache
http://api.jquery.com/load-event/
You may want to try altering the attribute using the jquery .attr function. If I recall correctly the src tag of an image is an attribute not a property. Although both .prop and .attr do relatively the same function, to ensure consistent behavior between browsers you may want to use the .attr tag instead.
$('#imageToChange').attr('src', '/path/image2.png');
As far as the delay goes, this could be due to the size of the image. The browser has to make a GET request to the server for the image and then paint the DOM with it. If the image is large, it could cause a time lapse between when the code changes the source and when the new image is properly written to the DOM. If the image is large, you may want to consider scaling it down or optimizing it for web use.
Hope this helps.
You can pre-load the image using the Javascript Image object.
In the head of your document put
<script type="text/javascript">
img2 = new Image();
img2.src = "/path/image2.png";
</script>
when you change the src of the image you fetch another image file. it makes an HTTP request for the new image, so it needs to load before showing it. could this be it?
btw, for this reason you can pre-load the image with js. either add
<img src="path/to/image.jpg" style="display: none" />
to your html or using JS
var im = new Image(1,1);
im.src = "path/to/image.jpg";
this way the image will be cached
It's the delay of network. Try this:
<div>
<div><img id="imageToChange" src="/path/image.png" /></div>
<div id="textToChange">Text</div>
</div>
<img src='/path/image2.png' style='display:none'>
it is likely the load time of your images. if this is the case, loading the image the first time should be the only slow one. a follow up load, after changing the image to something else, would be fast.
$('#imageToChange').prop('src', '/path/image1.png');
//slow, need to fetch image
$('#imageToChange').prop('src', '/path/image2.png');
//slow, need to fetch image
$('#imageToChange').prop('src', '/path/image1.png');
//fast, it already has this image
As a solution, you could try preloading your images. Or, better yet, use css sprites.