Continually request image until found - javascript

I am working on an interface that allows for an image to be uploaded asynchronously, and the process is working as expected. The process submits the image to a backend process that manages resizing the image to different sized and stores them on the cloud. i generate the url, and eventually the image is uploaded (usually in less than 10 seconds) to the appropriate resize.
After the image is uploaded, there's no thumbnail displayed for that image in the interface, obviously, because it hasn't been resized yet.
What I'd like to do, is, after creation of the image, and submission to the backend service for resize, a process on the client attached to each upload attempt (which I am thinking of using a setinterval for) to keep looking for that image until it resolves, and once it does resolve, update the thumbnail placeholder with that image.
Once the image does resolve by request, how do I feed that to update the interface?

Pure JavaScript using the setTimeout, onerror and onload events:
var img,
attempt = 2;
checkForImage("https://ssl.gstatic.com/apps/cpanel/resources/img/apps_logo_new.png3",
document.getElementById("message"));
function checkForImage(location, loadto) {
img = document.createElement("img")
img.onerror = function () {
setTimeout(function() {
checkForImage(location, loadto);
loadto.innerText = "Finding Picture... Attempt: " + attempt++;
}, 5000);
}
img.src = location;
img.onload = function () {
loadto.innerHTML = "<img src='" + location + "' />";
}
}
Removing the 3 at the end of the image link will show a successful example.

Depending on how you determine there is no image there (404 error, some sort of API returning JSON with a URL?), you could use jQuery.ajax() to quite easily act based on the HTTP status code.
function waitforimage(imageURL) {
$.ajax(url, {
statusCode: {
// on 404 wait and do it again later
404: function() {
setTimeout(function(){
waitforimage(imageURL);
}, 3000);
},
// on success, load the image
200: function() {
loadimage(imageURL);
}
}
});
}
function loadimage(imageURL) {
$('#myimageID').attr('src', imageURL);
}
Of course, you can do it without jQuery, but there'll be more fiddling around to get it working.

Related

How do I make a webpage think its images are done loading?

To give you some background, many (if not all) websites load their images one by one, so if there are a lot of images, and/or you have a slow computer, most of the images wont show up. This is avoidable for the most part, however if you're running a script to exact image URLs, then you don't need to see the image, you just want its URL. My question is as follows:
Is it possible to trick a webpage into thinking an image is done loading so that it will start loading the next one?
Typically browser will not wait for one image to be downloaded before requesting the next image. It will request all images simultaneously, as soon as it gets the srcs of those images.
Are you sure that the images are indeed waiting for previous image to download or are they waiting for a specific time interval?
In case if you are sure that it depends on download of previous image, then what you can do is, route all your requests through some proxy server / firewall and configure it to return an empty file with HTTP status 200 whenever an image is requested from that site.
That way the browser (or actually the website code) will assume that it has downloaded the image successfully.
how do I do that? – Jack Kasbrack
That's actually a very open ended / opinion based question. It will also depend on your OS, browser, system permissions etc. Assuming you are using Windows and have sufficient permissions, you can try using Fiddler. It has an AutoResponder functionality that you can use.
(I've no affiliation with Fiddler / Telerik as such. I'm suggesting it only as an example and because I've used it in the past and know that it can be used for the aforementioned purpose. There will be many more products that provide similar functionality and you should use the product of your choice.)
use a plugin called lazy load. what it does is it will load the whole webpage and will just load the image later on. it will only load the image when the user scroll on it.
To extract all image URLs to a text file maybe you could use something like this,
If you execute this script inside any website it will list the URLs of the images
document.querySelectorAll('*[src]').forEach((item) => {
const isImage = item.src.match(/(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|jpeg|gif|png|svg)/g);
if (isImage) console.log(item.src);
});
You could also use the same idea to read Style from elements and get images from background url or something, like that:
document.querySelectorAll('*').forEach((item) => {
const computedItem = getComputedStyle(item);
Object.keys(computedItem).forEach((attr) => {
const style = computedItem[attr];
const image = style.match(/(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|jpeg|gif|png|svg)/g);
if (image) console.log(image[0]);
});
});
So, at the end of the day you could do some function like that, which will return an array of all images on the site
function getImageURLS() {
let images = [];
document.querySelectorAll('*').forEach((item) => {
const computedItem = getComputedStyle(item);
Object.keys(computedItem).forEach((attr) => {
const style = computedItem[attr];
const image = style.match(/(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|jpeg|gif|png|svg)/g);
if (image) images.push(image[0]);
});
});
document.querySelectorAll('*[src]').forEach((item) => {
const isImage = item.src.match(/(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|jpeg|gif|png|svg)/g);
if (isImage) images.push(item.src);
});
return images;
}
It can probably be optimized but, well you get the idea..
If you just want to extract images once. You can use some tools like
1) Chrome Extension
2) Software
3) Online website
If you want to run it multiple times. Probably use the above code https://stackoverflow.com/a/53245330/4674358 wrapped in if condition
if(document.readyState === "complete") {
extractURL();
}
else {
//Add onload or DOMContentLoaded event listeners here: for example,
window.addEventListener("onload", function () {
extractURL();
}, false);
//or
/*document.addEventListener("DOMContentLoaded", function () {
extractURL();
}, false);*/
}
extractURL() {
//code mentioned above
}
You want the "DOMContentLoaded" event docs. It fires as soon as the document is fully parsed, but before everything has been loaded.
let addIfImage = (list, image) => image.src.match(/(http(s?):)([/|.|\w|\s|-])*\.(?:jpg|jpeg|gif|png|svg)/g) ?
[image.src, ...list] :
list;
let getSrcFromTags= (tag = 'img') => Array.from(document.getElementsByTagName(tag))
.reduce(addIfImage, []);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", doSomething);
} else { // `DOMContentLoaded` already fired
doSomething();
}
I am using this, works as expected:
var imageLoading = function(n) {
var image = document.images[n];
var downloadingImage = new Image();
downloadingImage.onload = function(){
image.src = this.src;
console.log('Image ' + n + ' loaded');
if (document.images[++n]) {
imageLoading(n);
}
};
downloadingImage.src = image.getAttribute("data-src");
}
document.addEventListener("DOMContentLoaded", function(event) {
setTimeout(function() {
imageLoading(0);
}, 0);
});
And change every src attribute of image element to data-src

Checking if the image is loaded within specific timespan

I'm trying to load image with JS and give it a certain time to load. For example 1 second. If the image wasn't loaded within 1 second - use default image. Here's what I have so far:
function displayUserImage() {
setTimeout(function(){
var imageMe = new Image();
imageMe.onload = function(){
$('#user-img-me').css('background-image', 'url(' + imageMe.src + ')');
};
imageMe.onerror = function() {
imageMe.src = "images/defaultImage.png";
}
if(!isEmpty(myObject.getPic()) && !isBlank(myObject.getPic())) {
imageMe.src = myObject.getPic();
}
else {
imageMe.src = "images/defaultImage.png";
}
}, 0);
}
I'm setting timeOut of 0 only to make the image loading asynchronous and not to interfere with execution of rest of the code. myObject.getPic() returns a string with image path. The image may be located on a remote domain/server. The connection might be slow, the image might be heavy, the server may not respond... So I want to give this image only a second to load, and if it didn't succeed - use default image. In both cases I need to set external variable imageMeLoaded to true once either image is loaded. Can it be done?

How to wait for images loaded with javascript?

I have a div in which I am appending imgs. Images are loading with AJAX by 20 items. They are showing with jQuery animation. A problem that animation is retarding. I think that there are 2 problems:
Images for showing are not downloaded and i want to display them now
When I set css display: block to img, I get delay when browser painting image
So the question is how to wait for pack of images (20 items) is downloaded and how to dispose of the painting delay?
P/S. If I show empty divs (just set them background-color) or 1 image for all img-tags the animation works quickly.
You can use this snippet. It doesn't depend on any library and is working well for our projects.
/*
* Preload an image if not cached, then call a callback function
* #param {String} the image url
* #param {Function} the callback function
*/
function loadImg(url, fn) {
var img = new Image();
img.src = url;
if (img.complete) { // If the image has been cached, just call the callback
if (fn) fn.call(img, true);
} else {
img.onerror = function() { // If fail to load the image
if (fn) fn.call(img, false);
};
img.onload = function() { // If loaded successfully
if (fn) fn.call(img, true);
//On IE6, multiple frames in a image will fire the 'onload' event for multiple times. So set to null
img.onload = null;
};
};
}
For your scenario, you can pass in a callback function like:
var callback = function(loaded) {
if (loaded === true) {
// do the animation.
var img = this; // now `this` points to the image itself.
} else {
// show default image or 'image failed to load'.
}
}
You can use my jQuery plugin to wait for the images to download in your new element.
$('#container').waitForImages().done(function() {
$(this).addClass('ready');
});
Use .complete of javascript
<img src="http://www.zastavki.com/pictures/originals/2013/Photoshop_Image_of_the_horse_053857_.jpg" id="something" />
var myVar = setInterval(function(){
console.log("loading")
if( document.getElementById("something").complete ) { // checks if image is loaded
console.log( "loaded" );
clearInterval(myVar);
}
}, 500);
here is jsfiddle demo.
You can either preload the images ahead of time (so they are all ready in the cache and won't have any delay when loading) or you can load them when needed and use a notification when they are loaded before starting the animation. Either way, you need to make sure the images are loaded before starting the animation if you want a smooth running animation.
You can see these other references for how to preload images with code samples. The first reference supports a callback that will get called when all the images have been loaded:
Image preloader javascript that supports events
Is there a way to load images to user's cache asynchronously?
How do you cache an image in Javascript

Downloading multiple images with Phonegap - FileTransfer

I have built an offline app in Phonegap, the JSON data gets pushed and gets to where it needs to go. But there are always a bunch of images that need to follow, and html5 cache will just not do it seeing it clears when an app is closed. I have been breaking my nugget on this for quite a while now.
The issue is that you want to check if the image exists on the file system. I've chosen to do so with a "async:false" AJAX call, and therefore have the code running up to a point. I haven't used the phonegap (almost hack) way by writing and setting overwrite to false (which produces an error) seeing that was another async function I didn't want to deal with (wherein lies the problem: async).
Another problem is that the Phonegap browser allows best for 3 downloads at the time (looked it up). My previous function was suffering from this debacle as it would just cut off downloading images if the amount simultaneous downloads was to high, which was around 20 to 40 (depending on size) images at the time (which of course is not strange seeing download speed plummets when you divide it over multiple downloads at the time).
So the question is, how to build:
A function that loops through JSON data (image variables).
Downloads them three at the time (and set the meta data because Apple told it had to)
Deletes from disk those who are not needed anymore (this last one is problem all over the inet as far as I've read, so we'll keep this optional and because by now I really don't actually care about space anymore).
Should run a function when all images are downloaded.
My code as far:
var datadir = "";
var pics_at_the_time = 0;
var external_url_pics = "http://Folder on server where images are";
// new_config.pics holds the JSON data. Built: '[ key (same as id) { "id": 1234567890, "tld":"jpg" }'. id+'.'+tld = the image name.
window.requestFileSystem( // get the root folder path
LocalFileSystem.PERSISTENT,
0,
function(fileSystem) {
datadir = fileSystem.root.fullPath;
},
function() {
console.log("Could not get root FS");
}
);
function fetch_images() {
var len = new_config.pics.length; // amount of pictures that need to be here
var all_in_counter = 0;
$.each(new_config.pics,function(index,val){ // loop through all pics
pic_exists(val);
});
}
function pic_exists(val) {
$.ajax({ // pic on disk or not
async:false,
url: 'file://'+datadir+'/'+val.id+'.'+val.tld, //or your url
success: function(){
var obj = val.id;
delete new_config.pics.obj;
},
error: function(){
var obj = val.id;
delete new_config.pics.obj;
downloadImage(val);
}
});
}
function downloadImage(val){
if(pics_at_the_time < 3) { // only 3 at a time. else wait for a download to finish
pics_at_the_time++;
var ft = new FileTransfer();
ft.download(
external_url_pics+val.id+'.'+val.tld,
datadir + "/" + val.id+'.'+val.tld,
function(entry) {
if(debug_console) { console.log("download complete: " + entry.name); }
entry.setMetadata(function(metadata) { } , function(error) { console.log("Could not set meta data: "+val.id); }, { "com.apple.MobileBackup": 1}); // no apple cloudbackup for these pics. We can always re-download apparently
pics_at_the_time--;
fetch_images();
},
function(error) {
if(debug_console) { console.log("download error target " + error.target); }
pics_at_the_time--;
fetch_images();
});
}
}
As you can probably tell, the code is not very sophisticated and it definitely does not check for already existing images. Cause although this works, it is far from perfect seeing it reloops the bunch every time, which at first seemed like a good idea. But now I'm having second thoughts.
Any help is obviously appreciated

How to monitor an image source for fully loaded status

I am loading a large number of images into a dynamic DIV and I am using a preloader to get the images.
imageObj = new Image();
imageObj.src = imgpath + imgname;
Each of these events creates a GET that I can see and monitor in Firebug.
If I know the name and path of an image, can I watch the relevant XMLHttpRequest to see if the GET has completed?
I do not want to rely on (or use) .onload events for this process.
The pseudo would look something like this...
if (imageObj.GET = 'complete')
Has anyone had any experience of this?
EDIT 1
Thanks to the help from Bart (see below) I have changed my image preloader to store an array of the image objects...
function imagePreLoader(imgname) {
images[imgnum] = new Image();
images[imgnum].src = imgpath + imgname;// load the image
imgnum ++;
}
And then, after all my other functions have run to build the content DIVs, I used the image.complete attribute in the following...
var interval = setInterval(function () {
imgcount = imgnum - 1; // because the imgnum counter ++ after src is called.
ok = 1;
for (i=0; i<imgcount; i++) {
if (images[i].complete == false){
ok = 0;
}
}
if (ok == 1) {
clearInterval(interval);
showIndexOnLoad();
}
}, 1000);
This waits until all the images are complete and only triggers the showIndexOnLoad() function when I get the 'ok' from the interval function.
All images now appear as I wanted, all at once with no additional waits for the GETs to catch up.
Well done Bart for putting me on to the image.complete attribute.
You can watch the complete property of the image to see if the image is fully loaded or not.
Here's an example.
http://jsfiddle.net/t3esV/1/
function load (source) {
var img = new Image();
img.src = source;
console.log('Loading ' + source);
var interval = setInterval(function () {
if (img.complete) {
clearInterval(interval);
complete(img);
}
}, 400);
};
function complete(img) {
console.log('Loaded', img.src);
document.body.appendChild(img);
};
Note: This example fails to clear the interval when something goes wrong and complete is never set to true.
Update
I wrote a simple jQuery.preload plugin to take advantage of the image.complete property.
This is a very interesting problem, and I am afraid there is no actual solution to this. The load event for images is when the image is being rendered and the browser knows the width and height of it.
What you would be after would be a tag-applicable readystatechange event. Alas, only IE allows you to bind those to non-document elements, so this is not an option.
There are a bunch of plug-ins that allow you to go around it, as well. One pretty hot one is https://github.com/desandro/imagesloaded , which has the added advantage of dealing with all the browser differences very efficiently. It, however, still relies on the load event (and I am pretty sure this is the only way to start doing what you want to do).

Categories

Resources