Javascript Fetch API status returning undefined - javascript

With the deprecation of XMLHttpRequest, I have been trying to rewrite a javascript function that checks if a url exists by using Fetch. My console log results in the correct value, but my return statement is always undefined. What am I doing wrong?
function urlExists(url) {
var request = new Request(url);
fetch(request).then(function(response) {
console.log(response.status);
return response.status != 404;
});
}
EDIT: I jumped the gun on a bug based on this error message in console [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. My bug was actually elsewhere in my code. Sorry for the confusion!

The problem is that you trying to do a sync operation by writing an async code. Both return statements in your code are relevant to their respective scope. You need to have a callback to return the response from fetch.
function urlExists(url, callback) {
var request = new Request(url);
fetch(request).then(function(response) {
console.log(response.status);
callback(response.status != 404);
});
}
/* Usage */
urlExists('http://example.com', (isExist) => {
if(isExist) {
console.log('URL found');
}
console.log('URL not found');
})

The code you have provided does not handle error part. Hence, That might be the reason it was not working.
function urlExists(url) {
var request = new Request(url);
return fetch(request).then(function(response) {
return (response.status != 404);
}, function(error){
return false;
});
}
urlExists("https://jsonplaceholder.typicode.com/todos/1").then(result=>{ console.log(result); });
urlExists("https://google.com").then(result=>{ console.log(result); });
I have tested this and working fine.

Convert it into this
function urlExists(url) {
return new Promise((resolve,reject)=>{
var request = new Request(url);
fetch(request).then(function(response) {
resolve(response.status != 404);
});
});
}
To Use It
urlExists("https://www.google.com").then(result=>{
console.log(result);
});

Your function returns a promise, so make sure you're using await or .then(...) in outer code to access the response correctly

Related

Value is always undefined returning from promise

I am currently working with the blackberry dynamics SDK.
I am currently using the http request functionality for the SDK but every time I want to return a response from a http call its always undefined - I tried promisifying it to return a value but to no avail.
It originally used two callbacks - which would rightly return me undefined, but if I make it a promise should it not return me a value.
Code
function constructGDHttpPostRequest(reqObj) {
let PostRequest = window.plugins.GDHttpRequest.createRequest("POST", URI + reqObj.endPoint, 30, false);
PostRequest.addRequestHeader('Content-Type', 'application/json');
PostRequest.addHttpBody(reqObj.body);
return SendRequest(PostRequest).then(function (httpRes) {
console.log(httpRes);
return httpRes;
})
}
function SendRequest(Request) {
return new Promise(function (resolve) {
resolve(Request.send(sendSuccess));
})
}
function sendSuccess(response) {
console.log("Received valid response from the send request");
let Response = window.plugins.GDHttpRequest.parseHttpResponse(response);
return JSON.parse(Response.responseText);
}
I have tried using some of the questions asked relating to something like this but it still returned undefined from the promise.
Cheers in advance.
As per #Nikos M. suggestion this is what ave done and now works as expected.
I needed to resolve the callback in order to return a value.
I would like to make the callback a little cleaner with some suggestions.
function constructGDHttpPostRequest(reqObj) {
let PostRequest = window.plugins.GDHttpRequest.createRequest("POST", URI + reqObj.endPoint, 30, false);
PostRequest.addRequestHeader('Content-Type', 'application/json');
PostRequest.addHttpBody(reqObj.body);
return SendRequest(PostRequest).then(function (httpRes) {
console.log(httpRes);
return httpRes;
})
}
function SendRequest(Request) {
return new Promise(function (resolve) {
Request.send(function (response) {
resolve(JSON.parse(window.plugins.GDHttpRequest.parseHttpResponse(response).responseText));
});
})
}

Await javascript recursive function to return true

So I'm using puppeteer in nodeJS and I have a function that recursively calls itself until a specified page is correctly loaded:
const isPageAccessible = async (page, url) => {
var pageRes = await page.goto(url, {
timeout: 10000
}).catch(e => console.log(e));
if (!pageRes || pageRes.status !== 200) {
console.log("Website didn't load properly.")
isPageAccessible(page, url);
} else {
console.log("Loaded!")
return true;
}
}
The problem here is that this function is returning undefined after the first recursive call (which is normal as far as I know since async functions must resolve with a value). I want the code to wait until this function resolves with true
console.log(await isPageAccessible(page,LOGIN_URL));
console.log("Done!")
So the console would log "Done!" after the website has been loaded succesfully. Right now it is logging "Done!" even if the website hasn't been loaded since isPageAccessible function is returning undefined after the first call.
Any thoughts on how to solve this would be appreciated!
You need to return the recursive call up the Promise chain:
if (!pageRes || pageRes.status !== 200) {
console.log("Website didn't load properly.")
return isPageAccessible(page, url);
}
Instead use this npm module,
https://www.npmjs.com/package/sync-request
var request = require('sync-request');
var res = request('GET', 'http://example.com');
console.log(res.getBody());
console.log("Done!")
All the statements will be executed one after another after completion.
Lesser code i guess!!

How to check status-code of URL of the application in protractor test?

I am using request package to request the url and using deferred promise :
getMonitoredPageName = function () {
var deferredExecutor = protractor.promise.defer();
var defer = protractor.promise.defer();
request('http://google.com',
function (error, response, body) {
if (error || response.statusCode ==400) {
defer.reject(response.statusCode);
} else {
defer.fulfill(response.statusCode);
}
});
return defer.promise;
}
And i am calling above function from test as :
it('should log the page name of every page view in the wizard', function () {
// We opened the first page of the wizard and we expect it to have been logged
expect(heartBeatNotification.getMonitoredPageName()).toBeTruthy(true);
//expect(heartBeatNotification.getMonitoredPageName()).toBe(400);
//browser.controlFlow().execute(heartBeatNotification.getMonitoredPageName);
})
Problem is test case always succeeds no matter what url has given. Need to write test case to check Application is running or not.
Any non-zero status code will be "truthy" so you need to adjust your test case. Make it check that the response is either explicitly 200, or maybe even just check thats its anything 2xx because that's still successful.
expect(heartBeatNotification.getMonitoredPageName()).toEqual(200);
Or just check that its greater than 200 or less than 300 etc.
expect(heartBeatNotification.getMonitoredPageName()).toBeGreaterThanOrEqual(200);
expect(heartBeatNotification.getMonitoredPageName()).toBeLessThan(300);
Also, minor note, you might want to review the logic on your first if block.
if (error || response.statusCode ==400) {
defer.reject(response.statusCode);
}
If there was an error, there might not be a response.statusCode (not positive). Might be better to just reject with the error itself
I was able to get the test working this way. It's a little simplified over what you were trying to do but it should help you figure it out. One thing to note, the way you have your if block setup has issues. If response is undefined the test will timeout and the promise will never return. Anyhow, here is how I was able to get your test working.
it('should return status code 200', async () => {
const url = 'http://google.com';
await heartBeatNotification.getMonitoredPageName(url).then(statusCode => {
expect(statusCode).toEqual(200);
}, () => {
fail('app not started');
});
});
Here is the function:
getMonitoredPageName = (url) => {
const defer = protractor.promise.defer();
request(url, (err, response, body) => {
if(err) {
defer.reject();
} else {
defer.fulfill(response.statusCode);
}
});
return defer.promise;
}

Node JS: Returning Data with Callback Function from API using http

I'm starting to learn Node.js and I am trying to build an app with the Express framework that will query the Coinbase API and get data on the price of Bitcoin.
I have been struggling with one thing though and because I am new to callback functions on node it does not help.
I am able to fully query the API and get the data but when it comes to somehow returning the price, it always comes back as "undefined".
I had this problem previously with simple queries that did not use callbacks so I assumed it was to do with the lack of the callback. However, I am still getting the same problem now and I have tried numerous iterations. I can't seem to find a solution. Any help would be appreciated.
var url = 'https://api.coinbase.com/v2/prices/spot?currency=USD';
function makeCall (url, callback) {
https.get(url,function (res) {
res.on('data', function (d) {
callback(JSON.parse(d));
});
res.on('error', function (e) {
console.error(e);
});
});
}
function handleResults(results){
return Number((results.data.amount))*14.5;
}
console.log(makeCall(url, function(results){
handleResults(results);
}));
makeCall() doesn't actually return anything. So when you call:
console.log(makeCall(url, function(results){
handleResults(results);
}));
you are writing the immediate return value of makeCall() (which is undefined) to the console. The return from your handleResults() happens too late for the console.log() to get.
It take a little getting used to. But you need to make sure when you need a value from an async callback, you wait to access it. For example this would work:
function handleResults(results){
console.log(Number((results.data.amount))*14.5;)
}
Learning to use promises can makes some of this more intuitive and easier to read.
Using promises you could write it like:
const https = require('https')
var url = 'https://api.coinbase.com/v2/prices/spot?currency=USD';
function makeCall (url) {
return new Promise((resolve, reject) => {
https.get(url,function (res) {
res.on('data', function (d) {
resolve(JSON.parse(d));
});
res.on('error', function (e) {
reject(e)
});
});
})
}
function handleResults(results){
return Number((results.data.amount))*14.5;
}
makeCall(url)
.then(function(results){
console.log(handleResults(results))
})
.catch(console.log)

How to wait for N number of async functions to finish in node.js so that I can do some work on all their combined results?

Please look at the code below. the request module is this one(https://www.npmjs.com/package/request)
var urlArray = []; // URL in this level
foo ("xyz.com", false);
function crawl (url, finished) {
request(url, function (error, response, body) {
if (finished == true) { return; }
// do some work on body (including getting getting n number of new URLS from
// the body) and set finished = true if we find what we are looking for.
// for each new url urlArray.push(newURL);
// for each new url call crawl(newurl, finished);
// Now How can I know when ALL these requests have finished?
// so that I can have a urlArray corresponding to this level of crawling tree and
// do some work before starting next level of crawl.
});
}
use Promises.
Check out the Q library (specifically I pointed to the methods you need):
Promise creation:
https://github.com/kriskowal/q/wiki/API-Reference#qdefer
var promise = Q.defer();
doAsyncStuff(callbackOfAsync);
return promise.promise;
functioncallbackOfAsync(isSuccess){
if(isSuccess){
promise.resolve();
}
else{
promise.reject();
}
}
Wait for multiple promises:
https://github.com/kriskowal/q/wiki/API-Reference#promise-for-array-methods
Q.all([getFromDisk(), getFromCloud()]).done(function (values) {
assert(values[0] === values[1]); // values[0] is fromDisk and values[1] is fromCloud
});
I don't really understand your question, but I guess you will need Promises. I assume you are using NodeJS.
function makeRequest (url) {
return new Promise(function (resolve, reject) {
request(url, function (err, response, body) {
if (err || response.statusCode !== 200)
reject(err || body);
else
resolve(body);
}
})
}
this function returns a promise. You can use it this way:
var request = makeRequest('url.com');
request.then(function (urls) {
// this is called if no error occured
urls.forEach(function (url) {
console.log (url);
});
}, function (error) {
// this is called on error
console.log (error);
});
If you want to wait for multiple requests to be answered to perform an action, use Promise.all:
var requests = [makeRequest(url1), makeRequest(url2), makeRequest(url3)];
Promise.all(requests).then(function (data) {
// everything is done
console.log(data);
});
I didn't test the code, but I hope you get the idea.
To answer your question specifically, the following flow of logic should work for you, I have added comments to help it make sense to you:
var urlArray = []; // URL in this level
var finished = false;
foo("xyz.com", false);
function start() {
while (urlArray.length) {
crawl(urlArray.pop());
}
}
function crawl(url) {
request(url, function (error, response, body) {
if (finished) {
return;
}
// 1. at this point, a given batch of crawls have all started
// AND urlArray is empty.
// 2. do some work on body (including getting getting n number of new URLS from
// the body) and set finished = true if we find what we are looking for.
// 3. for each new url urlArray.push(newURL);
// 4. start crawling on new batch of URL set
start();
});
}
All the request callbacks will be executed after start() completes, this guarantees that urlArray will be empty then.
If processing of one crawl response indicates (by setting finished = true;) that what you're looking for has been found all other processing of responses will terminate as soon as they begin.
Otherwise, reponse is processed and a new batch of urls are set for crawling. You call start() to begin crawling each.
It would help you also (as suggested in the other answer) if you acquainted yourself with the concept of Promises.

Categories