NodeJS never join on second await function - node.js

I've a main function that call other 2 functions with await.
The first one will download an image locally,
the second one will upload an image on our CDN with an Axios call, and wait his JSON response.
But when the first one will complete the main function going out, and not join on the second.
I need to join it
Note: Anyway the console.log('Middle') still never printed!
async function main(){
console.log('[1] Joined in the main()');
let url_immagine = 'https://www.castrol.com/content/dam/castrol/country-sites/en_gb/united-kingdom/home/motorcycle-engine-oils/engine-oil-brands/power1-racing-4t-10w-40.png.img.500.medium.png';
let filename = 'motor_oil.png';
let id = 122;
await downloadImagefromRemote(url_immagine, filename);
console.log('middle');
await putImageOnCloud(id, filename);
}
this is my JSFiddle script:
Code

You could just not await the second function.
putImageOnCloud(id, filename)
You say you dont want to wait for it, but you still use await.

Related

Why Redis get in async function is too slow?

I have a code that looks like the following
console.time('setfoo')
redis.set('foo', 'bar')
...
let result = await redis.get('foo')
console.timeEnd('setfoo')
Response time for this get is 263ms but when I remove await it goes down to 0.037ms What could be the reason?
Using await basically means "wait for this instruction to be completed before you do anything else".
Not using it would make your script execute quickly, but the result variable will only contain an unresolved Promise. More on promises here
In this case, redis does not use Promises natively, await is not needed.
What I don't get is your bit of code here:
let result = await redis.get(
redis.get('foo')
)
You pass a call to redis as a parameter to another call to redis. Redis natively uses callbacks, so if you want to display the variable you got from redis, try:
let result = await redis.get('foo', (result) => { console.log(result) })
Also, since redis.set() is asynchronous, by the time you try to recover your data, 'foo' might not have been set yet.
This might help you use promises with redis
EDIT: Your code re-written according to the redis documentation
const { promisify } = require("util");
const getAsync = promisify(client.get).bind(redis);
const setAsync = promisify(client.set).bind(redis);
...
console.time('setFoo')
await setAsync('foo', 'bar')
...
let result = await getAsync('foo', 'bar')
console.timeEnd('setfoo')
Just to throw my 2 cents here: V8 (the JavaScript engine behind browsers and NodeJS) is using an event-loop (powered by libuv) which does not necessarily execute tasks on a separate thread. What this event loop does is essentially accepting jobs and executing them when it can. More info on the event loop here.
With that being said, .get call adds a task to the event loop, which translates into a JavaScript Promise object. If you do not await that, the task is just added to the event loop. From your example:
console.time('foo')
let result = redis.get('foo')
console.timeEnd('foo')
What you are actually measuring here is how much time does it take for the event loop task to be submitted?, which is insignificant.
Awaiting on the .get call will not only add the task to the event loop, but also block until the task executes:
console.time('foo')
let result = await redis.get('foo')
console.timeEnd('foo')
So, to answer your question: the two times should not be equal at all, because one example is measuring how long it takes for Redis to process the request and return the result, while the other example is measuring just how long it takes for the job to be submitted to the event loop.

how to keep sending requests one after the other in nodejs

I am using puppeteer to automate a website, puppeteer session may take about (30s-60s), and I want to fire a request(open another puppeteer session) right after the one before it finishes and I realized that I can't use setInterval because time is not constant in my case, how can I achieve such thing
Use a recursive function to keep calling the same function right after it's done.
async function bot(){
const browser = await puppeteer.launch()
// other code
await browser.close()
}
async function fireMyRequest(){
await bot()
await fireMyRequest()
}

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.

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

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
}

Resources