How to bring out the request-promise result to the outside scope? - node.js

How to bring out the request-promise result to the outside scope?
I don't know why my bot echo 10 instead of 100.
enter image description here
This is the result I tried to get with await
enter image description here

In your code, change rp().then... to await rp().then... Js is asynchronous. While the rp() function runs, it takes some time. So, the code below it gets executed in that time.Hence, value of abc is never changed from inside the rp() function.

I'd recommend reading a bit more about promises and async/await in JavaScript, but to answer your question:
Your getAreaWeather() function is an async function, so you don't need to use an ES6 promise chain (.then() and .catch()), and you need to actually make sure your rp() promise resolves before you return anything. Your current function is setting abc to 10, then starting the request in rp(), but it immediately returns abc (which still equals 10 because the request hasn't finished yet)
This is just an example of how to fix the promises; I don't know if there are any issues with the HTML parsing.
async function getAreaWeather() {
var abc = 10;
var weathers = [];
var options = {/*what you have in your screenshot*/};
try {
// Wait for the rp() promise to resolve
var $ = await rp(options);
// Use $ however you want...
abc = 100;
return abc;
} catch (err) {
console.error(err);
}
// You could also return abc here if you want, but be aware it'll still equal 10 if the rp() throws an error
}

Related

NestJS async await requirement

I am trying out NestJS for the first time.
The question is simple, when I DO NOT use async await in my controller, I am able to return the data without await as async/await is used in the repository class methods
#Get('/:id')
getMessage(#Param('id') id: string) {
const messageId = id;
// works just fine 👇
const message = this.messagesService.findOne(messageId);
return message;
}
But when I make use of NotFoundException from NEST to make sure if I found the data I am supposed to return, I am forced to use async/await because without it, it considers the message to be always there. Which I am assuming is a Promise.
#Get('/:id')
async getMessage(#Param('id') id: string) {
const messageId = id;
// 👇 await
const message = await this.messagesService.findOne(messageId);
if (!message) {
throw new NotFoundException('Message with ID not found');
}
return message;
}
And if I do not use await, it does not throw an exception.
The question is, why/how does it work in the first example without the use of await
The await keyword returns a Promise. Therefore if you return a Promise you have satisfied the contract of returning a Promise.
I presume that Nest.js repository methods need to return a Promise. You have two choices. Either use the async keyword or return a Promise. In the first example you have returned a Promise so that is why it works.
Note that you don't need to use async if you don't want to. You can always go old school. This is what your first example would be like with the logic to check the message:
#Get('/:id')
getMessage(#Param('id') id: string) {
const messageId = id;
// works just fine 👇
const promise = this.messagesService.findOne(messageId).then((message) => {
if (!message) {
throw new NotFoundException('Message with ID not found');
}
else {
return message;
}
});
return promise;
}
We know that in JS, program runs synchronously and findOne is a webAPI provided by the browser. As it is a webapi it will first send the line
const message = this.messagesService.findOne(messageId);
to the api and will return that function again to stack once all the data is received.
(Assuming you know how the event loop and api works in JS)
In the first function you are not checking the variable message(if it is true or false) you are just returning the value so it will return only if the value is present.
But in second function you are checking the var message, if that line is written without the await it will directly go to the "if" statement even before the data is received from the api(findOne) at that time message var would still be undefined. So once you write await, stack will not go to the next line unless the answer from api is received, and at time your if statement will be checked perfectly.
The answer to your question is in the architecture of nestjs/node itself. If you return a promise (your first case) it resolve it and then returns the value. To get more clear idea about this check jiripospisil on 3 Aug 2018 on this issue.

Stripe promise pending even though it's async/await

I have a separate file created to facilitate stripe-based functions called stripe.js.
In this file I want to create a function that retrieves session object, so I initialize stripe with my test key and create function that I export as so:
const stripe = require('stripe')('my_stripe_key_here');
export async function obtainSession(sid) {
return await stripe.checkout.sessions.retrieve(sid);
}
Now in the App.vue I first import the function and try to use it:
import { obtainSession } from "./stripe/stripe";
let session = obtainSession(this.session_id)
.then(session=> {
return session
});
console.log(session)
And all I get is a pending promise in the console (Promise < pending >)
I've tried for a few days and tested different approaches from stackoverflow and elsewhere but I cannot seem to get this promise resolved. I am using a valid and existing session ID with no result.
Can anybody tell me what's the problem? Thanks!
let session = obtainSession(this.session_id)
.then(session=> {
return session
});
Doing this doesn’t mean this will return after the then- it will return immediately with the Promise returned by obtainSession. The continuation will also run once the promise resolves, but that return is basically meaningless in this flow.
You will have to await this call. Or if you log inside the then you’ll see the result.
You could consider retrieving this and awaiting inside mounted or similar, or have the code set session as a module variable. But in all cases this is going to be something that returns a promise you have to wait for outside of tHat assignment.

Nodejs loop through array of urls in a synchronous way

i've worked with node now for 2 years but cannot solve the following requirements:
I have an array of ~ 50.000 Parameters
I need to loop through the array and make a get request to always the same url with the parameter added
I need to write the result of the url-call back to the array
It's needed to do this one by one, as i can not call the api with several threads.
I'm sure there is a simple solution for that but everything i tried didn't make the code wait for the get request to return. I know that doing things synchronous in node is not the way we should to things, but in this special situation it is by design that the process shall not go on till the result comes back.
Any hint appreciated
Regards
Use a for loop, use a means of doing the GET request that returns a promise (such as the got() library) and then use await to pause the for loop until your response comes back.
const got = require('got');
const yourArray = [...];
async function run() {
for (let [index, item] of yourArray.entries()) {
try {
let result = await got(item.url);
// do something with the result
} catch(e) {
// either handle the error here or throw to stop further processing
}
}
}
run().then(() => {
console.log("all done");
}).catch(err => {
console.log(err);
});

Node.js waiting for an async Redis hgetall call in a chain of functions

I'm still somewhat new to working with Node and def new to working asynchronously and with promises.
I have an application that is hitting a REST endpoint, then calling a chain of functions. The end of this chain is calling hgetall and I need to wait until I get the result and pass it back. I'm testing with Postman and I'm getting {} back instead of the id. I can console.log the id, so I know that this is because some of the code isn't waiting for the result of hgetall before continuing.
I'm using await to wait for the result of hgetall, but that's only working for the end of the chain. do I need to do this for the entire chain of functions, or is there a way to have everything wait for the result before continuing on? Here's the last bit of the logic chain:
Note: I've removed some of the logic from the below functions and renamed a few things to make it a bit easier to see the flow and whats going on with this particular issue. So, some of it may look a bit weird.
For this example, it will call GetProfileById().
FindProfile(info) {
var profile;
var profileId = this.GenerateProfileIdkey(info); // Yes, this will always give me the correct key
profile = this.GetProfileById(profileId);
return profile;
}
This checks with the Redis exists, to verify if the key exists, then tries to get the id with that key. I am now aware that the Key() returns true instead of what Redis actually returns, but I'll fix that once I get this current issue resolved.
GetProfileById(profileId) {
if ((this.datastore.Key(profileId) === true) && (profileId != null)) {
logger.info('GetProfileById ==> Profile found. Returning the profile');
return this.datastore.GetId(profileId);
} else {
logger.info(`GetProfileById ==> No profile found with key ${profileId}`)
return false;
}
}
GetId() then calls the data_store to get the id. This is also where I started to use await and async to try and wait for the result to come through before proceeding. This part does wait for the result, but the functions prior to this don't seem to wait for this one to return anything. Also curious why it only returns the key and not the value, but when I print out the result in hgetall I get the key and value?
async GetId(key) {
var result = await this.store.RedisGetId(key);
console.log('PDS ==> Here is the GetId result');
console.log(result); // returns [ 'id' ]
return result;
}
and finally, we have the hgetall call. Again, new to promises and async, so this may not be the best way of handling this or right at all, but it is getting the result and waiting for the result before it returns anything
async RedisGetId(key) {
var returnVal;
var values;
return new Promise((resolve, reject) => {
client.hgetall(key, (err, object) => {
if (err) {
reject(err);
} else {
resolve(Object.keys(object));
console.log(object); // returns {id: 'xxxxxxxxxxxxxx'}
return object;
}
});
});
}
Am I going to need to async every single function that could potentially end up making a Redis call, or is there a way to make the app wait for the Redis call to return something, then continue on?
Short answer is "Yes". In general, if a call makes an asynchronous request and you need to await the answer, you will need to do something to wait for it.
Sometimes, you can get smart and issue multiple calls at once and await all of them in parallel using Promise.all.
However, it looks like in your case your workflow is synchronous, so you will need to await each step individually. This can get ugly, so for redis I typically use something like promisify and make it easier to use native promises with redis. There is even an example on how to do this in the redis docs:
const {promisify} = require('util');
const getAsync = promisify(client.get).bind(client);
...
const fooVal = await getAsync('foo');
Makes your code much nicer.

For loop in redis with nodejs asynchronous requests

I've got a problem with redis and nodejs. I have to loop through a list of phone numbers, and check if this number is present in my redis database. Here is my code :
function getContactList(contacts, callback) {
var contactList = {};
for(var i = 0; i < contacts.length; i++) {
var phoneNumber = contacts[i];
if(utils.isValidNumber(phoneNumber)) {
db.client().get(phoneNumber).then(function(reply) {
console.log("before");
contactList[phoneNumber] = reply;
});
}
}
console.log("after");
callback(contactList);
};
The "after" console log appears before the "before" console log, and the callback always return an empty contactList. This is because requests to redis are asynchronous if I understood well. But the thing is I don't know how to make it works.
How can I do ?
You have two main issues.
Your phoneNumber variable will not be what you want it to be. That can be fixed by changing to a .forEach() or .map() iteration of your array because that will create a local function scope for the current variable.
You have create a way to know when all the async operations are done. There are lots of duplicate questions/answers that show how to do that. You probably want to use Promise.all().
I'd suggest this solution that leverages the promises you already have:
function getContactList(contacts) {
var contactList = {};
return Promise.all(contacts.filter(utils.isValidNumber).map(function(phoneNumber) {
return db.client().get(phoneNumber).then(function(reply) {
// build custom object
constactList[phoneNumber] = reply;
});
})).then(function() {
// make contactList be the resolve value
return contactList;
});
}
getContactList.then(function(contactList) {
// use the contactList here
}, funtion(err) {
// process errors here
});
Here's how this works:
Call contacts.filter(utils.isValidNumber) to filter the array to only valid numbers.
Call .map() to iterate through that filtered array
return db.client().get(phoneNumber) from the .map() callback to create an array of promises.
After getting the data for the phone number, add that data to your custom contactList object (this is essentially a side effect of the .map() loop.
Use Promise.all() on the returned array of promises to know when they are all done.
Make the contactList object we built up be the resolve value of the returned promise.
Then, to call it just use the returned promise with .then() to get the final result. No need to add a callback argument when you already have a promise that you can just return.
The simplest solution may be to use MGET with a list of phone numbers and put the callback in the 'then' section.
You could also put the promises in an array and use Promise.all().
At some point you might want your function to return a promise rather than with callback, just to stay consistent.
Consider refactoring your NodeJS code to use Promises.
Bluebird is an excellent choice: http://bluebirdjs.com/docs/working-with-callbacks.html
you put async code into a for loop (sync operations). So, each iteration of the for loop is not waiting for the db.client(...) function to end.
Take a look at this stackoverflow answer, it explains how to make async loops :
Here

Resources