JS not waiting for Promise to be fulfilled? - javascript

I'm trying for my application to wait for the promise to return before executing other code, which is dependant on that data. For this I am using then(), but it is not working as expected, as the next code is still being executed, before my values are being returned.
I am using Express to handle requests and Axios to make my own requests.
index.js:
app.get('/api/guild/:serverId', async (req,res) => {
bot.getGuild(req.params.serverId).then((response) => { // It should here wait for the promise before executing res.send(...)...
res.send(response.data);
}).catch((error) => {
console.log(error) // Error: Returns that response is undefined
});
});
bot.js:
module.exports.getGuild = async function (id){
axios.get(BASE_URL + `guilds/${id}`, {
headers: {
'Authorization' : 'Bot ' + token // Send authorization header
}
}).then(function (response){ // Wait for response
console.log("Returning guild data")
return response; // Sending the response and also logging
}).catch(function (error){
console.log("Returning undefined.")
return undefined; // This is not being used in my problem
});
}
I already know that getGuild(id) is returning a working response. It also logs Returning guild data when returning the data. Yet this is being returned after index.js returning the error, that the response is undefined. Even though it should actually wait for the Promise to be fulfilled and then working with response.data.
Log:
TypeError: Cannot read property 'data' of undefined
at bot.getGuild.then (...\website\src\server\index.js:47:27)
at process._tickCallback (internal/process/next_tick.js:68:7)
Returning guild data

then is not needed in async functions because await is syntactic sugar for then.
getGuild doesn't return a promise from Axios, so it cannot be chained.
It should be:
module.exports.getGuild = function (id){
return axios.get(BASE_URL + `guilds/${id}`, {
...
The use of catch in getGuild is a bad practice because it suppresses an error and prevents it from being handled in caller function.

The getGuild function must wait for the axios promise in order to return a result:
try {
let res = await axios.get(BASE_URL + `guilds/${id}`, {
headers: {
'Authorization': 'Bot ' + token // Send authorization header
}
})
console.log("Returning guild data")
return res
} catch (exp) {
console.log("Returning undefined.")
return undefined;
}

Related

Capture request response code of rejected promises with Promise.allSettled

I'm using Promise.allSettled to call an array of URLs and I need to capture the response code of the request(s) of the rejected promise(s). Using the value of result.reason provided by Promise.allSettled is not accurate enough to assess the reason of rejection of the promise. I need the request response code (400, 500, 429, etc.).
I have so far the below:
var response = await Promise.allSettled(urls.map(url => fetch(url)))
.then(results => {
var data = [];
results.forEach((result, num) => {
var item = {
'req_url': urls[num],
'result': result.status,
'result_details': result
};
data.push(item);
});
return data;
});
How could I capture the response code of the request of the rejected promise and add it as a property within the returned array? The returned array should look ideally like this:
[{
'req_url': 'https://myurl.xyz/a',
'req_status_code': 400,
'result': 'rejected',
'result_details': {
'status': 'rejected',
'message': 'TypeError: Failed to fetch at <anonymous>:1:876'
}
},
{
'req_url': 'https://myurl.xyz/b',
'req_status_code': 419,
'result': 'rejected',
'result_details': {
'status': 'rejected',
'message': 'TypeError: Failed to fetch at <anonymous>:1:890'
}
},
{
'req_url': 'https://myurl.xyz/c',
'req_status_code': 429,
'result': 'rejected',
'result_details': {
'status': 'rejected',
'message': 'TypeError: Failed to fetch at <anonymous>:1:925'
}
}]
Any ideas?
fetch doesn't reject its promise on HTTP failure, only network failure. (An API footgun in my view, which I wrote up a few years back on my anemic old blog.) I usually address this by wrapping fetch in something that does reject on HTTP failure. You could do that as well, and make the failure status available on the rejection reason. (But you don't have to, see further below.)
class FetchError extends Error {
constructor(status) {
super(`HTTP error ${status}`);
this.status = status;
}
}
async function goFetch(url, init) {
const response = await fetch(url, init);
if (!response.ok) {
// HTTP error
throw new FetchError(response.status);
}
return response;
}
Then you could pass an async function into map to handle errors locally, and use Promise.all (just because doing it all in one place is simpler than doing it in two places with Promise.allSettled):
const results = await Promise.all(urls.map(async url => {
try {
const response = await goFetch(url);
// ...you might read the response body here via `text()` or `json()`, etc...
return {
req_url: url,
result: "fulfilled",
result_details: /*...you might use the response body here...*/,
};
} catch (error) {
return {
req_url: url,
result: "rejected",
result_status: error.status, // Will be `undefined` if not an HTTP error
message: error.message,
};
}
}));
Or you can do it without a fetch wrapper:
const results = await Promise.all(urls.map(async url => {
try {
const response = await fetch(url);
if (!response.ok) {
// Local throw; if it weren't, I'd use Error or a subclass
throw {status: response.status, message: `HTTP error ${response.status}`};
}
// ...you might read the response body here via `text()` or `json()`, etc...
return {
req_url: url,
result: "fulfilled",
result_details: /*...you might use the response body here...*/,
};
} catch (error) {
return {
req_url: url,
result: "rejected",
result_status: error.status, // Will be `undefined` if not an HTTP error
message: error.message,
};
}
}));

Fetch URL call shows Promise { <state>: "pending" }

Why this url fetch isn't working?
Actually this GET method is passing some error message to be stored:
fetch('http://www.govtschemes.in/pushlo90.php?msg=alert-bid:0.120148336001477231576473857578-Please%20enter%20correct%20captcha', {
method: 'get'
}).then(function(response) {
}).catch(function(err) {
// Error :(
});
However if I typein same URL ( http://www.govtschemes.in/pushlo90.php?msg=alert-bid:0.120148336001477231576473857578-Please%20enter%20correct%20captcha ) in browser it works.
Some other places in WebExension it's working properly.
But not working in another place. Also when I enter in Firefox console too it does not work. It shows some "pending.."
This function too is showing the same behavior:
function ff_httpGetAsync(theUrl, callback, failed_cb) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
// console.log("Successfully downloaded the ajax page");
if (callback) {
if (xmlHttp.responseURL == theUrl) {
callback(xmlHttp.response);
} else {
console.log("diff response url received" + xmlHttp.responseURL);
}
}
} else {
// console.log("Got status =", xmlHttp.status);
}
}
xmlHttp.open("GET", theUrl, true); // true for asynchronous
console.log("Gettiy :" + theUrl);
xmlHttp.send(null);
}
ff_httpGetAsync('http://www.govtschemes.in/pushlo90.php?msg=alert-bid:0.120148336001477231576473857578-Please%20enter%20correct%20captcha', function() {
}, function() {});
I've checked the server. In this case backend pushlo90.php isn't getting called.
Not sure what is wrong with my URL?
That result tells you the promise isn't answered yet. It might work in some occasions when the promise is handled very quickly, before the page is rendered.
Using a promise you basically say 'promise me you will do this'. This promise is either resolved or rejected. Before it's resolved or rejected, it's always pending.
Adding some logging in your first function should explain.
fetch('http://www.govtschemes.in/pushlo90.php?msg=alert-bid:0.120148336001477231576473857578-Please%20enter%20correct%20captcha', {
method: 'get'
}).then(function(response) {
console.log(response) //do something with response data the promise gives as result
}).catch(function(err) {
console.log(err)// Error :(
});
If you don't want to use the .then(), use async/await.
const functionName = async () => {
const result = await fetch(
"http://www.govtschemes.in/pushlo90.php?msg=alert-bid:0.120148336001477231576473857578-Please%20enter%20correct%20captcha",
{
method: "get"
}
);
console.log(result); //this will only be done after the await section, since the function is defined as async
};
functionName();
The fetch function return a promise that when resolved returns a HTTP response. You then can access the HTTP response Example:
fetch(`https://baconipsum.com/api/?type=all-meat&paras=2&start-with-lorem=1`)
.then(response => {
// HTTP response which needs to be parsed
return response.json()
})
// accessing the json
.then(json =>console.log(json))
So the question you have to ask yourself is: what is returned from the call??
Also be aware that 404 and other HTML error codes wont lead to a reject of the promise so don't bother with catch.
For more details see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
So, the code block that is shown in your question is -
fetch('http://www.govtschemes.in/pushlo90.php?msg=alert-bid:0.120148336001477231576473857578-Please%20enter%20correct%20captcha', {
method: 'get'
}).then(function(response) {
}).catch(function(err) {
// Error :(
});
So, what it says is fetch module will send a GET request to the URL provided in the request and the response or the error will go into the respective chained functions.
The error could be 404(Not found) or 401(Unauthorized) etc.
To check the error put some logging into your HTTP request handlers.
fetch('http://www.govtschemes.in/pushlo90.php?msg=alert-bid:0.120148336001477231576473857578-Please%20enter%20correct%20captcha', {
method: 'get'
}).then(function(response) {
console.log(`Response is {response}`)
}).catch(function(err) {
console.log(`Error is {err}`)
})
And for your other code here is the screenshot of what is getting returned from your code -
Where it clearly states 404 (Not found), hence your code will go in the error handler.

Fetch returns promise when I expect an array

I am doing a simple api get request, but I can't seem to isolate the array on its own. its always inside of a promise and I'm not sure how to remove it or how to access the values stored in the array.
function getLocation(name) {
let output = fetch(`http://dataservice.accuweather.com/locations/v1/cities/search?apikey=oqAor7Al7Fkcj7AudulUkk5WGoySmEu7&q=london`).then(data => data.json());
return output
}
function App() {
var output = getLocation(`london`);
console.log (output)
...
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Array(3)
is what is displayed in the console.log I require just the Array(3)
fetch, and Promise#then, always return a promise. To access the information it fetches, consume the promise:
getLocation()
.then(data => {
// use the data
})
.catch(error => {
// Handle/report the error
});
or in an async function:
const data = await getLocation();
Side note: Your getLocation has a very common error (so common I wrote it up on my anemic little blog): It doesn't check that the HTTP operation succeeded. fetch only fails on network errors, not HTTP errors. To fix it:
function getLocation(name) {
return fetch(`http://dataservice.accuweather.com/locations/v1/cities/search?apikey=oqAor7Al7Fkcj7AudulUkk5WGoySmEu7&q=london`)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error, status = " + response.status);
}
return response.json();
});
}

Node.JS recursive promise not resolving

i'm working with an API that allows me to sync data to a local DB. There is a syncReady API that I'm calling recursively until the sync batch is ready to start sending data. The recursion is working correctly and the .then callback is called, but the resolve function never resolves the response.
const request = require('request-promise');
const config = require('../Configs/config.json');
function Sync(){}
Sync.prototype.syncReady = function (token, batchID) {
return new Promise((res, rej) => {
config.headers.Get.authorization = `bearer ${token}`;
config.properties.SyncPrep.id = batchID;
request({url: config.url.SyncReady, method: config.Method.Get, headers: config.headers.Get, qs: config.properties.SyncPrep})
.then((response) => {
console.log(`The Response: ${response}`);
res(response);
}, (error) => {
console.log(error.statusCode);
if(error.statusCode === 497){
this.syncReady(token, batchID);
} else rej(error);
}
);
});
};
I get the 497 logged and the "The Response: {"pagesTotal";0}" response but the res(response) never sends the response down the chain. I've added a console.log message along the entire chain and none of the .then functions back down the chain are firing.
I hope I've explained this well enough :-). Any ideas why the promise isn't resolving?
Thanks!
First, you don't need to wrap something that returns a promise with a new Promise. Second, for your error case you don't resolve the promise if it is 497.
const request = require('request-promise');
const config = require('../Configs/config.json');
function Sync(){}
Sync.prototype.syncReady = function (token, batchID) {
config.headers.Get.authorization = `bearer ${token}`;
config.properties.SyncPrep.id = batchID;
return request({url: config.url.SyncReady, method: config.Method.Get, headers: config.headers.Get, qs: config.properties.SyncPrep})
.then((response) => {
console.log(`The Response: ${response}`);
return response;
})
.catch((error) => {
console.log(error.statusCode);
if(error.statusCode === 497){
return this.syncReady(token, batchID);
} else {
throw error;
}
})
);
};
Maybe something like the above will work for you instead. Maybe try the above instead. As a general rule of thumb, it's you almost always want to return a Promise.

Promise returns undefined

I know you can't make an asynchronous function behave synchronously but
how do I add some kind of order to my promises chain?
One result relies on the previous promise value and when that doesn't happen I get an undefined error. It's an http request so it is relying on external factors like how fast my connection can execute the request, etc.
module.exports.movieCheck = function(authToken) {
return request({
method : 'GET',
uri : 'https://graph.facebook.com/' + profileID + '/posts?fields=message&limit=25&' + authToken
}).spread(function (response, body) {
console.log('https://graph.facebook.com/' + profileID + '/posts?fields=message&limit=25&' + authToken);
return body;
}, function(e) {
console.log(e);
});
};
I am calling the above method as follows. However console.log returns undefined.
movieCheck.getToken()
.then(function(token) {
movieCheck.movieCheck(token);
})
.then(function(movies) {
console.log(movies); //should print json data
});
Terminal prints
undefined
https://graph.facebook.com/.../posts?fields=message&limit=25&access_token=....
Try to return the promise from the first then callback
movieCheck.getToken()
.then(function (token) {
return movieCheck.movieCheck(token);
}).then(function (movies) {
console.log(movies); //should print json data
});

Categories