Executing code asynchronously in JavaScript [duplicate] - javascript

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

Related

Promise-wrapping http request cannot be ended [duplicate]

This question already has answers here:
nodejs - How to promisify http.request? reject got called two times
(6 answers)
Closed 1 year ago.
const http = require("http");
async function sendRequest(url) {
url = new URL(url);
const requestDetails = {
'hostname': url.hostname,
'port': url.port || 80,
'path': url.pathname,
'method': 'GET'
};
const req = await new Promise((resolve, reject) => {
const request = http.request(requestDetails, response => {
const status = response.statusCode;
if (status === 200 || status === 201) {
console.log("SUCCESS");
resolve(request);
} else {
console.log("ERROR");
reject(`Status code returned was ${status}`);
}
});
});
req.end();
}
sendRequest('http://httpbin.org/get');
It works when req.end() is inside the promise, but after passing the request out then execute req.end(), the console is just holding without any response. I tried to compare "req === request" by a middle variable, it returned true. Why doesn't moving end() out work? Shouldn't these two object the same?
The purpose of the req.end() is to finish the request. We might be cautious that if any body part is unsent or might in progress, it will flush them in the stream, or if any request is chunked, this will send to terminating.
I have implemented your same code in a bit different and cleaner way. Below way might help to reuse the same code for multiple apis.
const http = require("http");
/**
* #description call the http request
*/
async function doHttp(requestDetails){
return new Promise((resolve, reject)=>{
http.request(requestDetails, response => {
const status = response.statusCode;
response.setEncoding("utf-8");
if (status === 200 || status === 201) {
console.log("SUCCESS");
response.on('data', data => {
return resolve(data);
});
} else {
console.error("ERROR");
return reject(new Error("emptyData"));
}
}).on('error', (err) => {
// Catch the error if occured in request
console.error(`problem with request: ${e.message}`);
return reject(err);
}).end();
});
}
/**
* #description sending the request
*/
async function doSend(url) {
url = new URL(url);
const requestDetails = {
'hostname': url.hostname,
'port': url.port || 80,
'path': url.pathname,
'method': 'GET'
};
const data = await doHttp(requestDetails)
console.log(data);
}
doSend('http://httpbin.org/get');
At last, we could say req.end() is required to finish up any request. It completely depends on us, how we can implement a method.
An alternate solution might be this native https module is such as Axios, superagent, got, node-fetch. They provide a wrapper over the native nodejs code which might help us to control to handle an error and response.
You should move the request.end call inside the promise otherwise it just newer gets called because you will be waiting for a promise that is newer resolved because the request is not send.
Also you should reject the promise in case request object emits error event.

Timing issue with http request on javascript [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm now trying to make get/post api request with axios javascript.But the problem is that my Api get function return the result before it receives data from server.here is my code
function Api(base_url) {
this.base_url = base_url;
}
Api.prototype = {
constructor: Api,
get: function (route) {
var url = this.base_url + route;
axios.get(url)
.then(
response => {
console.log(response.data.data);
return response.data.data;
})
return "hello";
},
post: function (route) {
}
}
And I call get function like this
api = new Api("http://localhost:8080/");
var data = api.get("post/get");
console.log(data);
Instead of waiting for reply from server,my function return "hello" as return data.Can someone help me why and how to solve this please?
Use this code:
Api.prototype = {
constructor: Api,
get: function (route) {
var url = this.base_url + route;
axios.get(url)
.then(function (response) {
console.log(response.data.data);
return response.data.data;
})
.catch(function (error) {
return "hello";
}
},
post: function (route) {
}
}
That's what it is supposed to do, I think.
I never used this Api, but with regular ajax requests, the function from which you send the request will return his value immediately independently from the request/response. The best way to do something once the request is completed, is to call what you need in the response callback.
AJAX requests are asynchronous, and there is no clean way to call a function wich executes an AJAX requests and make that very same function return your response data - unless you turn the AJAX request into a synchronous operations, but that's very very very bad practice.

Chain 2 HTTP requests and return 2nd promise

Before making an HTTP request, I need to check if the access credentials I have are valid. If they are not valid, I need to make a first HTTP request to revalidate them and, after completion, then a second HTTP request (the original one). The function call needs to return Angular's $http promise from the second HTTP request. Here's my function:
var makeRequest = function (scope, address, request, basic, form) {
startLoad(scope);
// Check if user is logged in and needs a new session token...
if (ready() && (now() > getSessionExpires()-20) ) {
// Setup auth.session.refresh request
var refreshRequest = {
"refreshToken": getRefreshToken(),
"clientID": getClientID(),
};
// Make auth.session.refresh request
$http.post(API + 'auth.session.refresh', format(refreshRequest))
.error(function (data) {
// If refresh request fails, logout and redirect to expired message
stopLoad(scope); logoff();
$window.location.href = '/error/expired';
return;
})
.success(function (data) {
// If refresh request succeeds, makeRequest is called recursively and the else condition runs
process(data, true);
return makeRequest(scope, address, request, basic, form);
});
} else { // if not logged in, or if session token is valid, run request function as usual
// Add Authorization header with valid sessionToken
if (ready()) $http.defaults.headers.post['Authorization'] = 'Bearer ' + getSessionToken();
// Basic Request: returns promise (if next context not set, can chain other action)
if (basic) {
return $http.post(API + address, request)
.error(function(data) {
if (data && scope) stopLoad(scope, data.message);
else if (scope) stopLoad(scope, Defaults.serverError);
else stopLoad();
if (form) resetForm(form);
})
.success(function(data) {
process(data);
if (scope) {
stopLoad(scope);
if (scope.context.next) $location.path(scope.context.next);
} else stopLoad();
if (form) resetForm(form);
});
}
// Custom Request: returns promise (can chain .error, .success)
else return $http.post(API + address, request);
}
};
When the token is found to be invalid, however, the function returns undefined, and I get an error that I cannot run .success() or .error(). The else functionality runs, but I'm wondering how I can ensure that I don't get this error. Thank you!
Just return the upper $http.post(/*...*/) and let promise chaining do it's magic:
return $http.post(API + 'auth.session.refresh', format(refreshRequest))
.catch(function (response) {
// If refresh request fails, logout and redirect to expired message
stopLoad(scope); logoff();
$window.location.href = '/error/expired';
})
.then(function (response) {
// If refresh request succeeds, makeRequest is called recursively and the else condition runs
process(response.data, true);
return makeRequest(scope, address, request, basic, form);
});
UPDATE: since .success/.error functions are not chainable (and have been flagged deprecated), you should use .then and .catch instead.
$http.post(/*...*/)
.success(function(data) {
/* do something with data */
})
.error(function(err) {
/*...*/
});
becomes
$http.post(/*...*/)
.then(function(response) {
/*do something with response.data */
})
.catch(function(response) {
/*...*/
});

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
});

How to break/return an Angular asynchronous call in AngularJS

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;
}

Categories