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
});
Related
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¶s=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.
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;
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I am currently learning how to use Angular.js and was attempting to write my own authentication code using a REST-like API. Below is the code for my authentication service.
The problem with my signIn function is that it always returns false, even when my api returns HTTP 200. After some time, I figured out that it is because of the synchronous nature of javascript that the return response; statement is executed before the response = res.data.key; statement.
I don't know how to execute the return statement after the assignment is complete (if the response is HTTP 200). How do I do this?
angular.module('app').factory('auth', ['Base64', '$http', function(Base64, $http) {
return {
signIn: function(email, password) {
var response = false;
var encoded = Base64.encode(email + ':' + password);
$http.defaults.headers.common.Authorization = 'Basic ' + encoded;
$http.post('api/v1/sign_in', {}).then(function(res) {
if (res.status == 200) {
response = res.data.key;
}
});
return response;
}
}
}]);
Use $q.defer():
angular.module('app').factory('auth', ['Base64', '$http', '$q', function(Base64, $http, '$q') {
return {
signIn: function(email, password) {
var response = false;
// You create a deferred object
// that will return a promise
// when you get the response, you either :
// - resolve the promise with result
// - reject the promise with an error
var def = $q.defer();
var encoded = Base64.encode(email + ':' + password);
$http.defaults.headers.common.Authorization = 'Basic ' + encoded;
$http.post('api/v1/sign_in', {}).then(function(res) {
if (res.status == 200) {
response = res.data.key;
// success: we resolve the promise
def.resolve(response);
} else {
// failure: we reject the promise
def.reject(res.status);
}
});
// You return the promise object that will wait
// until the promise is resolved
return def.promise;
}
}
}]);
Now, you can do:
auth.signIn().then(function(key) {
// signin successful
// do something with key
}).catch(function(err) {
// signin failed :(
// do something with err
}).finally(function() {
// you could do something in case of failure and success
})
You need to learn about promises: return the promise from the http post.
This may help
I am trying to work through JS Promises in node.js and don't get the solution for passing promises between different function.
The task
For a main logic, I need to get a json object of items from a REST API. The API handling itself is located in a api.js file.
The request to the API inthere is made through the request-promise module. I have a private makeRequest function and public helper functions, like API.getItems().
The main logic in index.js needs to wait for the API function until it can be executed.
Questions
The promise passing kind of works, but I am not sure if this is more than a coincidence. Is it correct to return a Promise which returns the responses in makeRequest?
Do I really need all the promises to make the main logic work only after waiting for the items to be setup? Is there a simpler way?
I still need to figure out, how to best handle errors from a) the makeRequest and b) the getItems functions. What's the best practice with Promises therefor? Passing Error objects?
Here is the Code that I came up with right now:
// index.js
var API = require('./lib/api');
var items;
function mainLogic() {
if (items instanceof Error) {
console.log("No items present. Stopping main logic.");
return;
}
// ... do something with items
}
API.getItems().then(function (response) {
if (response) {
console.log(response);
items = response;
mainLogic();
}
}, function (err) {
console.log(err);
});
api.js
// ./lib/api.js
var request = require('request-promise');
// constructor
var API = function () {
var api = this;
api.endpoint = "https://api.example.com/v1";
//...
};
API.prototype.getItems = function () {
var api = this;
var endpoint = '/items';
return new Promise(function (resolve, reject) {
var request = makeRequest(api, endpoint).then(function (response) {
if (200 === response.statusCode) {
resolve(response.body.items);
}
}, function (err) {
reject(false);
});
});
};
function makeRequest(api, endpoint) {
var url = api.endpoint + endpoint;
var options = {
method: 'GET',
uri: url,
body: {},
headers: {},
simple: false,
resolveWithFullResponse: true,
json: true
};
return request(options)
.then(function (response) {
console.log(response.body);
return response;
})
.catch(function (err) {
return Error(err);
});
}
module.exports = new API();
Some more background:
At first I started to make API request with the request module, that works with callbacks. Since these were called async, the items never made it to the main logic and I used to handle it with Promises.
You are missing two things here:
That you can chain promises directly and
the way promise error handling works.
You can change the return statement in makeRequest() to:
return request(options);
Since makeRequest() returns a promise, you can reuse it in getItems() and you don't have to create a new promise explicitly. The .then() function already does this for you:
return makeRequest(api, endpoint)
.then(function (response) {
if (200 === response.statusCode) {
return response.body.items;
}
else {
// throw an exception or call Promise.reject() with a proper error
}
});
If the promise returned by makeRequest() was rejected and you don't handle rejection -- like in the above code --, the promise returned by .then() will also be rejected. You can compare the behaviour to exceptions. If you don't catch one, it bubbles up the callstack.
Finally, in index.js you should use getItems() like this:
API.getItems().then(function (response) {
// Here you are sure that everything worked. No additional checks required.
// Whatever you want to do with the response, do it here.
// Don't assign response to another variable outside of this scope.
// If processing the response is complex, rather pass it to another
// function directly.
}, function (err) {
// handle the error
});
I recommend this blog post to better understand the concept of promises:
https://blog.domenic.me/youre-missing-the-point-of-promises/
I have the following project structure:
- PageController.js
- BusinessService.js
- NetworkManager.js
In my PageController I have the following call:
var getSomething = this._businessService.getMeSomething().then(function(response) {
alert("my response: " + response);
});
In my BusinessService:
getMeSometing: function() {
var user = this.getUserData();
if(user) {
var sendPromise = this._networkManager.getAnotherThing(user.id).then(function(response) {
alert("And another response: " + response);
});
} else {
$q.reject({ message: 'Rejecting this promise' });
}
},
The http calls are being made in the NetworkManager class.
So the problem here is that when I have no user data I want to break the call and so I'm using the reject.
This returns an error: Cannot read property 'then' of undefined regarding the call in PageController.
So, given my situtation, where if I have no userData, I want to cancel the request, how can I accomplish this?
Your call should return a promise. If there's a user, return the promise from getAnotherThing, otherwise, return the promise from $q.reject...
getMeSomething: function() {
var user = this.getUserData();
var sendPromise;
if(user) {
sendPromise = this._networkManager.getAnotherThing(user.id).then(function(response) {
alert("And another response: " + response);
// you probably want to return the data if successful (either response or response.data, depending on what response is)
return response.data;
});
} else {
sendPromise = $q.reject({ message: 'Rejecting this promise' });
}
return sendPromise;
}