Wait for second promise - javascript

Right now I'm learning promises and want to get a token from a webserver, which also uses a promise. I tried it before without a promise but it's also not working.
This is the first block.
promise = new Promise(resolve => {
let accessToken = helper.getAccessToken(baseUrl);
let userCollection = helper.createCollection("user", db);
let excersizeCollection = helper.createCollection("excercise", db);
resolve({
accessToken: accessToken,
database: {
userCollection: userCollection,
excersizeCollection: excersizeCollection
}
});
});
promise
.then(promises => {
console.log("my token" + promises.accessToken);
new nceDefaultbotCommands(bot, promises.accessToken, baseUrl);
new botComamnds(bot, promises.database);
let userController = new reqUserController(
baseUrl,
0,
promises.accessToken
);
bot.start();
})
.catch(() => {
console.log("error");
});
Only the access token is not working, this is in my helper class and it looks like this.
static getAccessToken(baseUrl) {
let promise = new Promise(resolve => {
request.post(
{
url: baseUrl + "/token",
body: {
credentials: {
user: "USER",
password: "PW"
}
},
json: true //// Automatically parses the JSON string in the response
},
(error, response, body) => {
if (error) console.log("error");
if (!error && response.statusCode === 200) {
resolve({ token: body.token });
}
}
);
});
promise.then(resolve => {
console.log(resolve.token);
return resolve.token;
});
}
I get the access token but normally after the then of the first promise.
Thanks in advance.

You're fulfilling your first promise with an object, so that object is the fulfillment value (the promise isn't magically resolved to the promises that are values of properties on that object).
There's no reason to use new Promise when you have a promise or promises to work with, just chain off them; in this case, via Promise.all:
Promise.all([
helper.getAccessToken(baseUrl),
helper.createCollection("user", db),
helper.createCollection("excercise", db)
])
.then(([accessToken, userCollection, exersizeCollection]) => { // Note the destructuring
console.log("my token" + accessToken);
new nceDefaultbotCommands(bot, accessToken, baseUrl);
new botComamnds(bot, {userCollection, exersizeCollection});
let userController = new reqUserController(baseUrl, 0, accessToken);
bot.start();
})
.catch(/*...*/);
Note I corrected the spelling of "exercise," which may require changes to your botCommands constructor.

You do not return your Promise:
static getAccessToken(baseUrl) {
let promise = new Promise(resolve => {
...
});
return promise.then(resolve => {
console.log(resolve.token);
return resolve.token;
});
}
Then I think you need to handle it like Promise, somewhat like:
promise = new Promise(resolve => {
let accessToken = helper.getAccessToken(baseUrl).then(token => {
let userCollection = helper.createCollection("user", db);
let excersizeCollection = helper.createCollection("excercise", db);
resolve({
accessToken: accessToken,
database: {
userCollection: userCollection,
excersizeCollection: excersizeCollection
}
});
});
});

Related

How to resolve or reject a promise from the result of another promise?

Really sorry if this has been answered, I've searched everywhere and can't find the exact problem I'm facing.
Take this as the example:
const fetchData = (email, password) => new Promise(async (resolve, reject) => {
await axios.post('https://api.something.com', {
email: email,
password: password,
},
{
headers: {
'Content-Type': 'application/json',
}
})
.then(res => {
cookie = res.headers['set-cookie'];
})
.catch(err => {
return reject('Login failed');
});
await axios.get('https://api.something.com', {
headers: {
'cookie': cookie
}
})
.then(res => {
data = res;
})
.catch(err => {
return reject('Failed to retrieve something');
});
return resolve(data);
});
If the login credentials are incorrect, the 'Login failed' reject is sent but the script will keep on running and there will be an additional error message saying that cookie isn't set. I want to completely stop the script in the first catch.
I could use throw new Error('Login failed') and that would stop the script completely but I don't feel like that's the right answer and also because it makes me wonder what else could I use to resolve the promise (for other purposes) and still don't let the script continue running.
I'm also not interested in nesting functions, to avoid promise-callback christmas tree-like hell.
Am I making sense?
Because you use async/await you don't need create a new Promise and instead of then/catch use try/catch;
const fetchData = async (email, password) => {
let cookie;
try {
const res = await axios.post(
"https://api.something.com",
{
email,
password
},
{
headers: {
"Content-Type": "application/json",
},
}
);
cookie = res.headers["set-cookie"];
} catch (err) {
throw new Error("Login failed");
}
let data;
try {
const res = await axios.get("https://api.something.com", {
headers: {
cookie
},
});
data = res;
} catch (err) {
throw new Error("Failed to retrieve something");
}
return data;
};
If you want to use the Promise API instead of async/await you can chain the promises: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#chaining

Resolving promise inside function causes a X(...) is not a function error

I'm working on load testing my API, but at some point I make a call to a different API.
Since I don't want to stress the second one, whenever I'm load testing I want to set a timeout and return an OK response like this:
function sendMessage(requestLib, blockApi, logger) {
if(!blockApi){
return (*my params*) => requestLib(`someURL`, {
headers: { Authorization: `Bearer ${token}` },
method: 'post',
data
});
}else{
logger.info("About to use the promise");
const response = returnOk.then(function() {
return new Response(200, {}, null, 'dummy.com');
});
return response;
}
}
returnOk is a Promise I defined earlier this way:
const returnOk = new Promise((resolve, reject) => {
setTimeout( function() {
resolve("Success!")
}, 2000)
});
And the function sendMessage is called inside a different function like this:
module.exports = ({ requestLib, Logger }) => async function(req, res) {
// Some unrelated code to decide if I'll call sendMessage
const response = await sendMessage(requestLib, blockApi, logger)(params);
// I log the response
res.end();
}
The regular flow works like a charm, but when I'm load testing and I get to returnOk.then()...
It throws
sendMessage(...) is not a function
If I remove the timeout and just return
return new Response(200, {}, null, 'dummy.com');
Things work just fine.
For some reason, your sendMessage(…) function returns another function:
return (*my params*) => …
You will need to do the same when mocking sendMessage:
function sendMessage(requestLib, blockApi, logger) {
if (!blockApi) {
return (*my params*) => requestLib(`someURL`, {
headers: { Authorization: `Bearer ${token}` },
method: 'post',
data
});
} else {
return (*my params*) => {
const returnOk = new Promise((resolve, reject) => {
setTimeout(resolve, 2000)
});
logger.info("About to use the promise");
return returnOk.then(function() {
return new Response(200, {}, null, 'dummy.com');
});
};
}
}
Btw, you really shouldn't have this boolean blockApi parameter to sendMessage. Write two distinct functions with the same signature, and use dependency injection in the code that is calling it.

Promise { <pending> } Error while working with Geoserver Rest API

Anyone has any idea about this and how would I be able to get the correct outcome?
I have used the Promise and async/await properties in here
layers = async () => {
return new Promise((resolve, reject) => {
let options = {
url: `http://geoserverIP/geoserver/rest/workspaces/datastores/featuretypes.json`,
auth: {
'user': 'admin',
'pass': 'geoserver'
}
}
request(options, (err, resp, body) => {
if (!err && resp.statusCode == 200) {
return resolve(JSON.parse(body))
} else if (!err) {
return reject({
status: 404,
errors: [{
messages: ["Workspace or datastore not found"]
}]
})
} else {
return reject({
status: 500,
errors: [{
messages: ["Failed connection with geoserver"]
}]
})
}
})
})
}
console.log(layers())
I expect to get the list of layers but I get "Promise {pending}"
When you mark a function as async by default returns a Promise also you are returning Promise explicitly.
To use the value either you can await the function or can make a .then chain.
(async ()=>{
const data = await layers();
console.log(data);
})();
or
layers().then((data)=>{
console.log(data)
});
Note: As you are not using any await keyword inside the function you don't need to mark it as async
EDIT1: You can use axios instead of request, it by default returns promise.

Subscribe http.post that is placed inside a promise Angular 6

It gets complicated to me when I mix the promise with subscribe and another async task together.
This is my auth service:
getCurrentUserToken(){
return new Promise((resolve,reject)=>{
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
resolve(idToken)
}).catch(function(error) {
reject(error)
});
})
}
This is my HTTP service:
sendEmail(email) {
return this.authService.getCurrentUserToken().then(token => {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic server-Password',
})
};
let data = email
data['idToken'] = token
return this.http.post(this.apiServer + 'sendEmail', data, httpOptions)
})
}
This is how I call the sendEmail(email) function at the component:
Observable.fromPromise(this.httpService.sendEmail(element)).subscribe(
data3 => {
console.log(data3)
}, error => {
console.log(error)
}
))
I have to pass currentUserToken to the API to let the API authenticate the user session. Still, both of the the getCurrentUserToken() sendEmail() are running in async, so I have to use Promise to pass the Token to sendEmail() function, and let the sendEmail function to call the API to send the email.
Without the promise, I am able to subscribe to the http.post like this:
this.httpService.sendEmail(element).subscribe(
data3 => {
console.log(data3)
}, error => {
console.log(error)
}
))
Unfortunately, I screwed it up when I added the promise into it, and the console.log is returning this:
Observable {_isScalar: false, source: Observable, operator: MapOperator}
Please advise on how to subscribe to the http.post that is placed inside the Promise.
There's seriously no need of Complicating things here.
I'll use async/await syntax here and for that, we'll have to work with Promises instead of Observables. Good thing is, we can leverage the toPromise() method on an Observable value to change it to a Promise
Focus on my comments in the code as well
Here's the implementation
For getCurrentUserToken
getCurrentUserToken() {
return firebase.auth().currentUser.getIdToken(true);
// This will already return a Promise<string>
// So no need to do a .then and then return from there.
}
For sendEmail
async sendEmail(email) {
// Since getCurrentUserToken returns a Promise<string> we can await it
const token = await this.authService.getCurrentUserToken();
// token will now have the Current User Token
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic server-Password',
})
};
let data = email
data['idToken'] = token
return this.http.post(this.apiServer + 'sendEmail', data, httpOptions).toPromise();
// Notice how we're calling the .toPromise() method here
// to change Observable into a Promise
}
How to use it?
This code will go in your Component Method where you were previously calling this.httpService.sendEmail. DO MAKE SURE TO MARK THAT FUNCTION AS async THOUGH.
// We can only await something in a function which is declared of type async
async sendEmail() {
try {
const data = await this.httpService.sendEmail(element);
// Since sendEmail again returns a Promise, I can await it.
console.log(data);
} catch (error) {
console.log(error);
}
}
Why don't we use Observable instead of Promises here.
getCurrentUserToken() {
return new Observable(obs => {
firebase
.auth()
.currentUser.getIdToken(/* forceRefresh */ true)
.then(function(idToken) {
obs.next(idToken);
obs.complete();
})
.catch(function(error) {
obs.error(error);
});
});
}
sendEmail(email): Observable {
return new Observable(obs => {
this.authService.getCurrentUserToken().subscribe(token => {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
Authorization: 'Basic server-Password'
})
};
let data = email;
data['idToken'] = token;
this.http
.post(this.apiServer + 'sendEmail', data, httpOptions)
.subscribe(
result => {
obs.next(result);
obs.complete();
},
error => {
obs.error();
}
);
});
});
}
// now call the service from Component like this.
this.httpService.sendEmail(element).subscribe(
data3 => {
console.log(data3)
}, error => {
console.log(error)
}
));

Structure of multiple nested Mongoose promises

How would I structure a function that has multiple Mongoose.findOne() nested in each other?
I need to do something like
const userId = '...';
const postId = '...';
const imageId = '...';
User.findById(userId).then(user => {
if (!user) {
return res.status(400).json({
status: 'error',
err: 'User not found',
});
}
Post.findById(postId).then(post => {
if (!post) {
return res.status(400).json({
status: 'error',
err: 'Post not found',
});
}
Image.findById(imageId).then(image => {
if (!image) {
return res.status(400).json({
status: 'error',
err: 'Image not found',
});
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
}).catch(err => { .. });
}).catch(err => { .. });
}).catch(err => { .. });
Since Collection.findById() returns a promise, I guess I should use chaining instead of this structure.
So it might be something like
User
.findById(userId)
.then(user => Post.findById(postId))
.then(post => Image.findById(imageId))
.then(image => {
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
});
.catch(err => { .. });
but I don't know how to access the variables user, post, and image, and how to throw the errors, so I can access them in my catch statement.
Edit
I have tried this
async function getPostAsync() {
const userId = '597989c668189f31483ffdbf';
const postId = '597989c62624ea74750c74f8';
if (!userId) {
throw new Error('User id missing');
}
if (!postId) {
throw new Error('Post id missing');
}
const user = await User.findById(userId);
const post = await Post.findById(postId);
return post;
}
app.get('/', (req, res) => {
getPostAsync().then(post => {
res.json({
status: 'success',
});
}).catch(err => {
res.status(400).json({
status: 'error',
err
});
})
});
but I just receive
{
"status": "error",
"err": {}
}
Am I doing something wrong?
But I get the same result even with
async function getPostAsync() {
throw new Error('msg');
return Post.find();
}
so I might be calling the async function wrong.
You can use Promise.all:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(result)=>{
let user = result[0];
let post = result[1];
let image = result[2];
})
.catch(err => { .. });
Or with destructing assignment:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(([user, post, image])=>{...})
.catch(err => { .. });
You can't access those variables inside a later promise's then, but you can get round it by assigning the local resolved values to global variables
let globalUser, globalPost; // create variables for later
User
.findById(userId)
.then(user => {
globalUser = user; // assign to global
return Post.findById(postId)
})
.then(post => {
globalPost = post; // assign to global
return Image.findById(imageId)
})
.then(image => {
// DO SOMETHING WITH VARIABLES 'globalUser', 'globalPost', AND 'image'
})
.catch(err => {... });
EDIT: or when using async/await:
async function() {
const user = await User.findById(userId);
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
// do something with user, post and image
}
Seeing as your promises don't rely on each other you could also use Promise.all() in an async function:
async function() {
const result = await Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
]);
const [user, post, image] = result;
// do something with user, post and image
}
EDIT 2: Error handling
async function getImage() {
let user;
try {
user = await User.findById(userId);
} catch (error) { // deal with rejection of `User.findById`
// do something with error
}
// if these fail the entire function will throw
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
return image;
}
getImage()
.then(image => {... })
.catch(error => {... }); // deal with rejection of `getImage` as a whole
The above code showcases the ways you can handle errors in an async function. The first is how we deal with an error in the User.findById function, by simply wrapping it in a try catch block.
The second method is by simply letting the entire async function throw an error. I.e. if the Post.findById or Image.findById promises reject, the entire getImage() promise will reject, which you can deal with in the .catch() handler.

Categories

Resources