Check if a image exists with a given URL - JavaScript - javascript

I'm trying to check if an image exists given a url using javascript, but my code is not working. Thanks!
Here's my function :
function verifyImageURL(url, callBack) {
var img = new Image();
img.src = url;
img.onload = function () {
callBack(true);
};
img.onerror = function () {
callBack(false);
};
}
And Here's how I call it:
var url = "http://greenstyle.com.br/wp-content/uploads/2012/09/Tucano-imagem-Silvia-Kochen-Wordpress.jpg";
verifyImageURL(url, function (imageExists) {
if (imageExists === true) {
alert("Image Exists");
} else {
alert("Image does not Exist");
}
});

This question hasn't had activity in a long time, but since I saw another recent answer, I thought I would share a solution which fits the asker's example pattern of using a callback, but alternatively returns a promise if no callback argument is provided:
See code in the TypeScript Playground to view types and the overloaded function signature
function loadImage (url, timeoutOrCallback, maybeCallback) {
let timeout;
let callback;
if (typeof timeoutOrCallback === 'number') {
timeout = timeoutOrCallback;
if (typeof maybeCallback === 'function') callback = maybeCallback;
}
else if (typeof timeoutOrCallback === 'function') callback = timeoutOrCallback;
const promise = callback
? undefined
: new Promise(resolve => void (callback = resolve));
const onlyRunOnce = {once: true};
let timerId = 0;
let done = false;
if (typeof timeout === 'number') {
timerId = setTimeout(() => {
done = true;
callback(false);
}, timeout);
}
const img = new Image();
img.addEventListener('load', () => {
if (done) return;
clearTimeout(timerId);
done = true;
callback(true);
}, onlyRunOnce);
img.addEventListener('error', () => {
if (done) return;
clearTimeout(timerId);
done = true;
callback(false);
}, onlyRunOnce);
img.src = url;
return promise;
}
// Usage examples:
function asyncExample (url, logId) {
const timeout = 3e3; // 3s
loadImage(url, timeout).then(imageLoaded => {
console.log(`${logId}: async with timeout:`, imageLoaded)
});
loadImage(url).then(imageLoaded => {
console.log(`${logId}: async:`, imageLoaded)
});
}
function callbackExample (url, logId) {
const timeout = 3e3; // 3s
let cb = imageLoaded => console.log(`${logId}: callback with timeout:`, imageLoaded);
loadImage(url, timeout, cb);
cb = imageLoaded => console.log(`${logId}: callback:`, imageLoaded);
loadImage(url, cb);
}
let url = 'https://i.stack.imgur.com/TxzmG.jpg';
asyncExample(url, 'SO image');
callbackExample(url, 'SO image');
url = 'https://invalid.example/image.jpg';
asyncExample(url, 'invalid image');
callbackExample(url, 'invalid image');

Try this approach
var x = new XMLHttpRequest(); x.open("get", url, true);x.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) {alert('exist');}else{alert('does not exist'};}; x.send();

Related

return true in nested function part of new Image() .onload to verify image exist from url?

How can I return true when function is run inside function part of new Image() .onload, in order to verify if a url is a valid image?
var valid = false;
checkImage('https://example.com/image.png')
console.log(valid) //always false at first run
function checkImage(url) {
var image = new Image();
image.onload = function () {
if (this.width > 0) {
valid = true;
}
}
image.onerror = function() {
valid = false;
}
image.src = url;
}
I also tried setting a global variable which doesn't work,Or any other way to return true / false back via checkImage(url) ?
Got this initial solution from https://stackoverflow.com/a/55880263/8719001
(async () => {
let valid = await checkImage('https://example.com/image.png')
console.log(valid)
})();
async function checkImage(url) {
return new Promise(resolve=>{
const image = new Image()
image.onload = () => resolve(!!image.width)
image.onerror = () => resolve(false)
image.src = url
})
}
Following your code example you'll need to wrap your result in a Promise, which is an object made for "returning a result later":
function checkImage(url) {
return new Promise((resolve, reject) => {
var image = new Image();
image.onload = function () {
if (this.width > 0) {
resolve()
} else {
reject()
}
}
image.onerror = reject
image.src = url;
})
}
const valid = await checkImage('https://example.com/image.png')
Alternatively, a simpler way of doing this would be to use fetch if your only goal is to check for the file's existence (and not necessarily checking whether it works as an image):
const exists = await fetch(url, {method: 'HEAD'})
.then(response => response.status === 200)

Issue with preloading assets to browser

I have a Nodejs App running on background and I have this code in frontend ( here it's simplified for you ) to preload videos , audios , etc ... to blobs like this:
function preloadOne(url, done) {
const xhr = new XMLHttpRequest();
xhrs.push(xhr);
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onprogress = event => {
if (!event.lengthComputable) return false;
let item = this.getItemByUrl(event.target.responseURL);
item.completion = parseInt((event.loaded / event.total) * 100);
item.downloaded = event.loaded;
item.total = event.total;
this.updateProgressBar(item);
};
xhr.onload = event => {
let type = event.target.response.type;
let blob = new Blob([event.target.response], {
type: type
});
let url = URL.createObjectURL(blob);
let responseURL = event.target.responseURL;
let item = this.getItemByUrl(responseURL);
item.blobUrl = url;
item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1);
item.type = type;
item.size = blob.size;
done(item);
};
xhr.onerror = event => {}
xhr.send();
}
Everything is going fine until I reach 32mb transferred then the transfer gets really slow and for the next 10 mb to load I need more time than what I needed to reach 30MBs!!??
Sometimes and not all the times I get this error for loading a video too:
Failed to load resource: net::ERR_HTTP2_PROTOCOL_ERROR
Here you can see the end of the fast part of the preloading where suddenly everything gets slow:
Any suggestions why this is happening and how to fix this is a good point to start and debug this and it's really appreciated ...
For me it seems something get's full after 30 MBs :)
UPDATE: it a more complete version of the code to have a look if you need it:
async function Preloading() {
preloadedPercent = 0;
setTimeout(() => startBlink(), 1500);
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof definer === 'function' && definer.amd ? definer(factory) :
(global.Preload = factory());
}(this, (function () {
'use strict';
function preloadOne(url, done) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onprogress = event => {
if(!event.lengthComputable) return false
let item = this.getItemByUrl(event.target.responseURL);
item.completion = parseInt((event.loaded / event.total) * 100);
item.downloaded = event.loaded;
item.total = event.total;
this.updateProgressBar(item);
};
xhr.onload = event => {
let type = event.target.response.type;
let blob = new Blob([event.target.response], { type: type });
let url = URL.createObjectURL(blob);
let responseURL = event.target.responseURL;
let item = this.getItemByUrl(responseURL);
item.blobUrl = url;
item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1);
item.type = type;
item.size = blob.size;
done(item);
};
xhr.onerror = event => {
console.log('Error Happend in Preloading');
reload();
};
xhr.send();
}
function updateProgressBar(item) {
var sumCompletion = 0;
var maxCompletion = this.status.length * 100;
for(var itemStatus of this.status) {
if(itemStatus.completion) {
sumCompletion += itemStatus.completion;
}
}
var totalCompletion = parseInt((sumCompletion / maxCompletion) * 100);
if(!isNaN(totalCompletion)) {
this.onprogress({
progress: totalCompletion,
item: item
});
}
}
function getItemByUrl(rawUrl) {
for (var item of this.status) {
if (item.url == rawUrl) return item
}
}
function fetch(list) {
return new Promise((resolve, reject) => {
this.loaded = list.length;
for (let item of list) {
this.status.push({ url: item });
this.preloadOne(item, item => {
this.onfetched(item);
this.loaded--;
if (this.loaded == 0) {
this.oncomplete(this.status);
resolve(this.status);
}
});
}
})
}
function Preload() {
return {
status: [],
loaded: false,
onprogress: () => {},
oncomplete: () => {},
onfetched: () => {},
fetch,
updateProgressBar,
preloadOne,
getItemByUrl
}
}
return Preload;
})));
const preload = Preload();
preload.fetch(preloadingData.preloadURLs).then(items => {});
preload.oncomplete = items => {
Media = generateMedia(items);
Blobs = generateBlobs(items);
sfx = getSfx();
preloadProgress(100, true);
preloadingData = null;
}
preload.onprogress = event => { preloadProgress(event.progress); }
preload.onfetched = item => {}
}
function preloadProgress(value, done) {
if(value > preloadedPercent || done) {
preloadedPercent = value;
checkRestart = 0;
checkLatency(value);
progressBar(value, done);
}
}

Make ts/js-library promise based

I've implemented this file reader into my project.
I would like to make this return a promise when it finishes with the file reading, but I don't know how to propagate the promise from there.
class MyClass {
constructor() {}
public start(file) {
parseFile(file);
}
private parseFile(file) {
let fileSize = file.size;
let chunkSize = 10000;
let offset = 0;
let self = this;
let readBlock = null;
// How do I get this success function to return a promise to the user?
let success = function() { return new Promise...? };
let onLoadHandler = function(evt) {
if (evt.target.error == null) {
offset += evt.target.result.length;
chunkReadCallback(evt.target.result);
} else {
chunkErrorCallback(evt.target.error);
return;
}
if (offset >= fileSize) {
success(file);
return;
}
readBlock(offset, chunkSize, file);
}
readBlock = function(_offset, length, _file) {
let r = new FileReader();
let blob = _file.slice(_offset, length + _offset);
r.onload = onLoadHandler;
r.readAsText(blob);
}
readBlock(offset, chunkSize, file);
}
}
Today it works like this:
let x = new MyClass();
x.start(file);
And I would like it to be like this instead:
let x = new MyClass();
x.start(file).then(() => { console.log('done') });
Where do I put my return Promise so that the user can handle the promise?
Thanks!
The following should turn readFile into a promise:
private parseFile(file,chunkSize,offset) {
let fileSize = file.size;
let self = this;
readBlock = function (_offset, length, _file) {
return new Promise(
function(resolve,reject){
let r = new FileReader();
let blob = _file.slice(_offset, length + _offset);
//https://developer.mozilla.org/en-US/docs/Web/API/FileReader/onload
r.onload = function(e){
if(e.target.error!==null){
reject(e.target.error);
}
else{
resolve(e.target.result)
}
};
//https://developer.mozilla.org/en-US/docs/Web/API/FileReader/onerror
r.onerror = function(err){
reject(err);
}
r.readAsText(blob);
}
)
}
return readBlock(offset, chunkSize, file);
}
You can have the caller define what the block size is and when to read the next block.
An example how to use this function:
x.parseFile(file,file.size,0)
.then(
function(textData){
console.log(textData);
}
);
//read in chunks of 1000
function readInChunks(file,chunkSize=1000,offset=0,data=""){
return x.parseFile(file,chunkSize,offset)
.then(
function(textData){
if(offset+chunkSize>=file.size){
return data+textData;
}
console.log("get next chunk");
//recursively call itself
return readInChunks(file,chunkSize,offset+chunkSize,data+textData);
}
)
}
//call read in chunks
readInChunks(file,/* optional, defaults to 1000 */500)
.then(
function(textData){
console.log("got data:",textData);
}
)

Javascript use return value in another function

What I want to achive is using the return value of the "previewfile" function as an execution indicator for the "readfiles" function. But this needs to be after the "image.onload" part has been executed, since there I need returnThis to be set to true.
I've researched several things on Google and Stackoverflow concerning this problem and callbacks / deferred objects in general, but I cannot wrap my head around how to applicate that in this situation.
I have the following constellation in my Image uploading section:
function previewfile(file, tests, acceptedTypes, holder) {
var returnThis = false;
if (tests.filereader === true && acceptedTypes[file.type] === true) {
var reader = new FileReader();
reader.onload = function (event) {
var image = new Image();
image.onload = function() {
var testimage = new Image();
testimage.src = $(this).attr('src');
var widthOfImage = testimage.width;
var heightOfImage = testimage.height;
if (!checkImageDimensions(widthOfImage, heightOfImage)) {
// do stuff
} else {
returnThis = true;
}
};
image.src = event.target.result;
holder.appendChild(image);
};
reader.readAsDataURL(file);
} else {
// do other stuff
}
return returnThis;
}
function readfiles(files, tests, acceptedTypes, holder, progress) {
var uploadNow = previewfile(files[0], tests, acceptedTypes, holder);
if (uploadNow === true) {
// do stuff
}
} else {
// do other stuff
}
}
I would go with something like this
function readfiles(files, tests, acceptedTypes, holder, progress) {
previewfile(files[0], tests, acceptedTypes, holder, function(value){
if (uploadNow === true){
// do stuff
}
else {
// do other stuff
}
});
}
function previewfile(file, tests, acceptedTypes, holder, callback) {
...
callback(returnValue); //instead of return
}
As previewfile() relies on asynchronous activity, it is itself effectively asynchronous. As such, it can't reliably return a value, but it can return a promise.
As others have pointed out, previewfile() can be written to accept a callback, which would avoid the need for a promise. However, if you want a promise solution, here is one (certainly not the only one).
function previewfile(file, tests, acceptedTypes, holder) {
if(tests.filereader === true && acceptedTypes[file.type] === true) {
var reader = new FileReader(),
image;
var promise_a = $.Deferred(function(dfrd) {
reader.onload = function(event) {
image.attr('src', event.target.result).appendTo(holder);
dfrd.resolve();
};
reader.onerror = function() {
dfrd.reject('fileReader error');
};
}).promise();
var promise_b = $.Deferred(function(dfrd) {
image = $("<img/>").on('load', function() {
var widthOfImage = image.width;
var heightOfImage = image.height;
if (checkImageDimensions(widthOfImage, heightOfImage)) {
dfrd.resolve();
} else {
//do stuff
dfrd.reject('image loaded but dimensions did not check out');
}
}).error(function() {
dfrd.reject('image did not load');
});
}).promise();
reader.readAsDataURL(file);
return $.when(promise_a, promise_b);
} else {
// do other stuff
// Also return a promise here, even if no async is involved.
}
}
readfiles() can now be written as follows :
function readfiles(files, tests, acceptedTypes, holder, progress) {
return previewfile(files[0], tests, acceptedTypes, holder).then(function() {
// do stuff
}).then(null, function(reason) {
console.log(reason);// or display to the user in the DOM.
// do other stuff
});
}
The benefit of a promise-based solution is maybe not so much in handling success as managing errors. Note how a single handler reports several different types of error.
With the help of FelixKling and kallehj, this is the working solution (with callback):
// important
function previewfile(file, tests, acceptedTypes, holder, callback) {
var returnThis = false;
if (tests.filereader === true && acceptedTypes[file.type] === true) {
var reader = new FileReader();
reader.onload = function (event) {
var image = new Image();
image.onload = function() {
var testimage = new Image();
testimage.src = $(this).attr('src');
var widthOfImage = testimage.width;
var heightOfImage = testimage.height;
if (!checkImageDimensions(widthOfImage, heightOfImage)) {
// do stuff
} else {
returnThis = true;
}
callback(returnThis); // important
};
image.src = event.target.result;
holder.appendChild(image);
};
reader.readAsDataURL(file);
} else {
callback(returnThis); // important
}
}
function readfiles(files, tests, acceptedTypes, holder, progress) {
// important
previewfile(files[0], tests, acceptedTypes, holder, function (uploadNow) {
if (uploadNow === true) {
// do stuff
}
} else {
// do other stuff
}
}
});

Exit function only when return is called

i have a input file which is used to upload images. However, I have to validate its size before upload. As below is the code I've tried on.
I have a parent function, that calls the method,ValidateImageSize( ):
$('input:file').change(function (e) {
if (ValidateImageSize(this))
// do something
else
alert("wrong size");
});
and the method shown as below:
var ValidateImageSize = function (input) {
var reader = new FileReader();
reader.onload = function (e) {
var img = new Image();
img.onload = function (e) {
return this.height == 40 && this.width == 40 ? true : false;
}
img.src = e.target.result;
}
reader.readAsDataURL(input.files[0]);
};
The method ValidateImageSize() always returns 'undefined' to its parents, cause it have yet executes the onload functions.
The output I need is either true/ false. Perhaps the structure of my codes itself is incorrect.
How can I solve this?
Use callback, something like as below:
var validation_callback = function(isValid) {
if (isValid) {
// do something
} else {
alert("wrong size");
}
};
$('input:file').change(function(e) {
ValidateImageSize(this, validation_callback);
});
var ValidateImageSize = function (input, callback) {
var reader = new FileReader();
reader.onload = function (e) {
var img = new Image();
img.onload = function (e) {
var isValid = this.height == 40 && this.width == 40 ? true : false;
callback(isValid);
};
img.src = e.target.result;
};
reader.readAsDataURL(input.files[0]);
};

Categories

Resources