Undefined returned from file existence check - javascript

I'm checking if a file at a certain local URL exists via a XMLHttpRequest, kind of a workaround peek at the filesystem. Using the pingFile function described below, I try to see if I get a 200 or 404 for a given file and perform some actions depending on that result.
function pingFile(theURL, callback)
{
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (this.readyState === this.DONE) {
if (callback !== null) {
return callback(this.status);
} else {
return this.status;
}
}
};
req.open("HEAD", theURL);
req.send();
}
var q = pingFile('images/image1.png', null);
However, when I check the value of q, it is always undefined. I'm missing something about the asynchronous nature of an XHR here, I think, but I haven't been able to find where to wait so that this.status has either of the values I would expect from a file check.
EDIT: I've tried adding return 4; after req.send(); and that always gives q the value 4 regardless of whether the file is there.
How do I get the status value of a XMLHttpRequest back from the function it's in?

For async operations you could use callbacks or promises. Here is a simple example with callbacks:
(function () {
function pingFile(theURL, success, error) {
var req = new XMLHttpRequest();
req.onload = function (e) {
if (this.status === 200) {
success(e);
} else {
error(e);
}
};
req.open("HEAD", theURL);
req.send();
}
function fileExist(e) {
alert('File exist!');
}
function fileNotExist(e) {
alert('File does not exist!');
}
pingFile('images/image1.png', fileExist, fileNotExist);
}());

Related

How to load a json file with javascript locally without Jquery?

I'm creating a website to progress in javascript and I have a little problem, every ways I try, my browser doesn't want to load my json file.
I tried many codes i found on internet but none of them work (or I don't know how to make them work). Finally i fond this one which is quite easy to understand but yhis one too doesn't work and always return an error message.
function loadJSON(path,success, error)
{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function()
{
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 1) {
if (success)
success(JSON.parse(xhr.responseText));
} else {
if (error)
error(xhr);
}
}
};
xhr.open("GET", path , true);
xhr.send();
}
function test()
{
loadJSON('test.json', function(data) { console.log(data); }, function(xhr) { console.error(xhr); });
}
I run the test function but everytimes, the console return me an error. Someone have an idea to solve my problem ?
status is the HTTP response code.
200 means the request has been successful. The status will most likely never be 1.
Here is a list of HTTP codes
As a solution, I suggest using the fetch API, which is the modern way to query files.
Here are some examples on how to use it
If you really want to use AJAX, use this :
var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
// Success!
var resp = this.response;
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
Source : You Might Not Need jQuery

How to store the results of an async (AJAX) function in a variable?

This is not a duplicate question.
It is a request help finding technical conclusion, that is not addressed in
How do I return the response from an asynchronous call?
If .then() is not resolving the Promise, how do I track down the problem at that point? It seems like I missed something technically, not conceptually.
This function retrieves data from a URL:
async function getINFO(source, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", source);
xhr.responseType = "document";
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200){
var text = xhr.responseXML.getElementsByTagName('pre')[0].innerHTML;
console.log(text);
callback(text);
}
}
xhr.send();
}
Externally defined callback:
function asyn_return(input){
console.log(input);
return input;
}
The data comes back perfectly in AJAX.
I want to populate an attribute member (datastore.info) with the data.
info is a URL string.
This is the place in the code where I use my AJAX data retrieval function:
if (typeof(info) === 'string'){
// If I have a URL retrieve the data and add it to the datastore object.
datastore.info = getINFO(info, asyn_return).then(data =>{
console.log(data);
return data;
});
//console.log(datastore.info);
} else {
datastore.info = "";
}
console.log(datastore.info);
console.log(data) returns the data I expect, but datastore.info is not populated:
{item1: "data", item2:"data", info: {} }
Not sure what I'm missing technically to have this resolve to the result.
Once I have the promise (the wrapper), what triggers it to resolve?
And when that is not happening, what is the likely issue?
Thanks to anyone who can help.
Your console.log at the end is assuming that the data comes un a sync manner, but its is not, therefore it is undefined, cause the ajax data is not arrived yet.
You will need to change your code to be an async one, it can be rewritten via promises or async/await.
It can be written like that:
function getINFO(source) {
return new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open('GET', source);
xhr.responseType = 'document';
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var text = xhr.responseXML.getElementsByTagName('pre')[0].innerHTML;
console.log(text);
resolve(text);
}
};
xhr.send();
});
}
if (typeof info === 'string') {
// If I have a URL retrieve the data and add it to the datastore object.
getINFO(info).then(data => {
console.log(data);
datastore.info = data;
// continue your async code here
});
//console.log(datastore.info);
} else {
datastore.info = '';
}

is there a way to easily check if the image url is valid or not?

I'm trying to write a function that checks if the image URL is an actual image, if it is it will return true, or else it will return false,
something like that:
checkImage(imageURL){
if imageURL.isReal{
return true
}
return false
}
I have found alot of answers but they didnt really work as boolean functions
The most elegant solution is using a XMLHttpRequest and check the response code.
If it's 200, the image exists, if it's something different it's highly possible that the picture - or more precise the url in general - doesn't exist.
Here's an example:
function checkImage(url) {
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.send();
request.onload = function() {
status = request.status;
if (request.status == 200) //if(statusText == OK)
{
console.log("image exists");
} else {
console.log("image doesn't exist");
}
}
}
checkImage("https://picsum.photos/200/300");
Well, as I said this is more a general approach.
If you want to be sure that it's actually an image, you can utilize the Image object's onerror and onload events.
function checkImage(url) {
var image = new Image();
image.onload = function() {
if (this.width > 0) {
console.log("image exists");
}
}
image.onerror = function() {
console.log("image doesn't exist");
}
image.src = url;
}
checkImage("https://picsum.photos/200/300");
You could possibly use the fetch API. A modern variant of XHR.
So like
async function checkImage(url){
const res = await fetch(url);
const buff = await res.blob();
return buff.type.startsWith('image/')
}
By this
checkImage('https://example.com/notAnImage.txt') // false
checkImage('https://example.com/image.png') // true
You could use getResponseHeader of XMLHttpRequest to check the mime type of the successfully returned content of your request. In fact you can't know the content of the response only based upon the http success response code of your request.
The XMLHttpRequest method getResponseHeader() returns the string
containing the text of a particular header's value. If there are
multiple response headers with the same name, then their values are
returned as a single concatenated string, where each value is
separated from the previous one by a pair of comma and space. The
getResponseHeader() method returns the value as a UTF byte sequence.
In this example, a request is created and sent, and a readystatechange
handler is established to look for the readyState to indicate that the
headers have been received; when that is the case, the value of the
Content-Type header is fetched. If the Content-Type isn't the desired
value, the XMLHttpRequest is canceled by calling abort().
var client = new XMLHttpRequest();
client.open("GET", "unicorns-are-teh-awesome.txt", true);
client.send();
client.onreadystatechange = function() {
if(this.readyState == this.HEADERS_RECEIVED) {
var contentType = client.getResponseHeader("Content-Type");
if (contentType != my_expected_type) {
client.abort();
}
}
}
All the best.

Understanding XHR request object in javascript... (confused)

I'm following a simple book and It says:
function createRequest()
{
try
{
request = new XMLHttpRequest();
}
catch (tryMS)
{
try
{
request = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (otherMS)
{
try
{
request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (failed)
{
request = null;
}
}
}
return request;
}
function getDetails(itemName)
{
var request = createRequest();
if (request==null)
{ alert("Unable to create request");
return;
}
var url= "getDetails.php?ImageID=" + escape(itemName);
request.open("GET",url,true);
request.onreadystatechange = displayDetails;
request.send(null);
}
function displayDetails()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
detailDiv = document.getElementById("description");
detailDiv.innerHTML = request.responseText;
}
}
}
And all this code above is fine and it's okay to me.. but after few pages it says:
ITS VERY IMPORTANT TO REMOVE VAR KEYWORD BEFORE request VARIABLE so the callback can reference the variable...
but how come in example above it worked? is it coincidence if we call a variable 'request' that it will map with global variable in a createRequest method?
Take a look on image below:
Why is this happening ? in one example var before request variable is used and everything is fine, in another var is avoided so the method in callback might access it.. but how come method in a callback is accessing a request variable in first example...
It's confusing because there are 2 similar examples, with different explanations..
EDIT
P.S it says request has to be a global ? :o
Thanks guys
Cheers
In both examples, implicit global variables are created so they can be shared with the callback.
When the second request variable is created, it creates a local variable inside the getDetails function. So when createRequest() returns the global variable, the local variable becomes a reference to it.
This is rather bad advice and shows a lack of understanding on the writers' part. But it seems to be an old text, since activeX objects are deprecated by now, so maybe globals used to be less frowned upon. The proper way is to either send the responseText or responseXML as a parameter to the callback or send the entire request as the parameter for the callback.
Maybe the writer didn't want to make the request code more complex, but imho, this is not a good way to teach people things.
function createRequest( method, url, callback, payload ) {
var request = new XMLHttpRequest();
if ( !request ) {
alert( "Unable to create request" );
return null;
}
request.open( method, url );
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200 ) {
callback( request.responseText );
}
};
request.send( payload );
};
function getDetails( itemName, callback ) {
createRequest( "GET", "getDetails.php?ImageID=" + escape(itemName), callback, null );
};
function displayDetails( detail ) {
var detailDiv = document.getElementById("description");
detailDiv.innerHTML = detail;
};
getDetails( "someItemName", displayDetails );
you are right, in your first example, function createRequest is not using var, which mean you are creating a global variable request when excute request = new XMLHttpRequest();.
We should avoid using gobal var in most situation.
function createRequest() {
try {
// add var so it's not global variable
var request = new XMLHttpRequest();
} catch (tryMS) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (otherMS) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
return request;
}
function getDetails(itemName)
{
var request = createRequest();
if (request==null)
{ alert("Unable to create request");
return;
}
var url= "getDetails.php?ImageID=" + escape(itemName);
request.open("GET",url,true);
// create anonymous function to call your callback and pass `request` as local variable
request.onreadystatechange = function(){
displayDetails(request);
};
request.send(null);
}
function displayDetails(request)
{
if (request.readyState == 4)
{
if (request.status == 200)
{
detailDiv = document.getElementById("description");
detailDiv.innerHTML = request.responseText;
}
}
}

Detect JSON exist

I have question about chechking file exists.
I have this piece of code.
function fileExists(url) {
if (url) {
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.send();
console.log("exists");
return true;
} else {
console.log("no exists");
return false;
}
}
But it says me that file is exists. But it doesn't exists. In fact on my URL is 404 error XML file. Is possible somehow detect if requested URL is JSON? I need to return true only if checked file is JSON.
Thank you
Since this is a synchronous request, you can just try to parse the responseText you get back and if it fails to parse, you know it's not JSON:
var res = req.responseText;
try {
res = JSON.parse(res);
console.log('json', res);
} catch (e) {
console.log('not json')
}
If it were not a synchronous request, this would work:
If you look at the XMLHttpRequest docs, you'll see that in order to receive data back from an XMLHttpRequest, you need to add a callback function:
xhr.onreadystatechange = function() {//Call a function when the state changes.
if(this.readyState == XMLHttpRequest.DONE && this.status == 200) {
// Request finished. Do processing here.
}
}
If you wanted to check if your request is JSON, you could do this:
xhr.onreadystatechange = function() {//Call a function when the state changes.
if(this.readyState == XMLHttpRequest.DONE && this.status == 200) {
var res = this.responseText;
try {
JSON.parse(res);
console.log('json', res);
} catch (e) {
console.log('not json')
}
}
}

Categories