cant return the chained promises result - node.js

const request = require('request-promise')
required this module and use it in this way the data and subData is options that i defined later...
const foo= (data, subData) => {
return request(data)
.then(result => {
console.log('result:',result)
return request(subData)
})
}
the problem is the request(data) result is not return but the request(subData) result is return
Q.allSettled([
foo(),
fo(),
f(),
.
.
.
])
and with q module create an array of promises, but i still cant get my expected return result

You can use any of the following methods to chain your promises and return both responses into an array
const foo = (data, subData) => {
let result;
return request(data)
.then(res => {
result = res;
return request(subData)
}).then(res => {
return [result, res]
});
}
//OR
const foo2 = (data, subData) => {
return request(data)
.then(res1 => {
return request(subData).then(res2 => {
return [res1, res2]
})
});
}
//OR
const foo3 = async (data, subData) => {
let res1 = await request(data);
let res2 = await request(subData);
return [res1, re2];
}

I would suggest the following approach instead of Promise Chaining or Q:
const fetchData = (data, subData) => {
const result = await request(data);
const resultSub = await request(subData);
console.log(result, resultSub);
};

Related

Getting right fetch result from previous async fetch API functions

Hi I don't understand why getFlyByTime() function is giving me an ERR_INVALID_URL.
All the way upto getFlyByTime() I am getting the right results and coordinates.
Any advice would be appreciated,
Thank you
import fetch from "node-fetch";
let myIP = ''
let myLocation = ''
let flyByInformation = ''
const findIP = 'https://api.ipify.org/?format=json'
const geolocation = 'http://ipwho.is/'
const issFly = `https://iss-pass.herokuapp.com/json?`
const getMyIP = async function() {
let response = await fetch(findIP);
let data = await response.json()
return data.ip
}
const getMyGeoLocation = async function() {
let response = await fetch(geolocation + myIP);
let data = await response.json()
let resURL = `https://iss-pass.herokuapp.com/lat=${data.latitude}&lon=${data.longitude}`
return resURL;
}
const getFlyByTime = async function() {
let response = await fetch(myLocation);
console.log(response)
let data = await response.json()
return data;
}
getMyIP()
.then(data => {
myIP = data
}).catch(err => console.log('gmi error', err))
getMyGeoLocation()
.then(data => {
myLocation = data;
console.log(myLocation);
}).catch(err => console.log('gml error', err))
getFlyByTime()
.then(data => {
flyByInformation = JSON.parse(data);
console.log('flyby', flyByInformation);
}).catch(err => console.log('gflt error', err))
You are trying to use the myLocation and myIP values BEFORE they have been filled. Your functions return a promise before their work is done. Not until that promise has been fulfilled are the resolved values available for you to use.
As such, you must sequence your operations. It is generally easiest to do this with await. Here's an example shown below:
import fetch from "node-fetch";
const findIpURL = 'https://api.ipify.org/?format=json'
const geolocationURL = 'http://ipwho.is/'
const issFly = `https://iss-pass.herokuapp.com/json?`
async function fetchJSON(url) {
const response = await fetch(url);
if (response.ok) {
return response.json();
} else {
throw new Error(`Request failed, status ${response.status}`, { cause: response });
}
}
async function getMyIP() {
const data = await fetchJSON(findIpURL);
return data.ip;
}
function getMyGeoLocation(myIP) {
return fetchJSON(geolocationURL + myIP);
}
async function getFlyInfo(lat, long) {
let resURL = `https://iss-pass.herokuapp.com/lat=${lat}&lon=${long}`;
const flyInfo = await fetchJSON(resURL);
return flyInfo;
}
async function getFlyByTime() {
const myIP = await getMyIP();
console.log(myIP);
const myLocation = await getMyGeoLocation(myIP)
console.log(myLocation.latitude, myLocation.longitude);
return getFlyInfo(myLocation.latitude, myLocation.longitude);
}
getFlyByTime().then(flyInfo => {
console.log(flyInfo);
}).catch(err => {
console.log(err);
});
When I run this, the last getFlyInfo() request ends up returning a text/plain response that just says "Not Found" and the status is a 404. So, either the URL isn't being built properly in my version of the code or something is amiss in that last part.
But, hopefully you can see how you sequence asynchronous operations with await in this example and you can make that last part do what you want it to.

Problem to use a Map in Firebase Functions

I am trying to get the length of a Map and I keep getting "undefined". Could please someone tell me what am I doing wrong?
This is the part of the code that gives me problems.
const GYMdetail: { [key: string]: number} = {};
GYMdetail[`${doc.data().name} (${doc.data().personalID})`] = 650;
const subtotal = 650 * GYMdetail.size;
This is the complete function code
export const addGymMonthlyExpense =
functions.https.onRequest((request, response) => {
const query1 = admin.firestore().collection("users");
const query = query1.where("subscriptions.gym.active", "==", true);
query.get()
.then(async (allUsers) => {
allUsers.docs.forEach(async (doc) => {
if (doc != undefined) {
const houseForGym = doc.data().subscriptions.gym.house;
await admin.firestore()
.doc(`houses/${houseForGym}/expenses/2022-04`)
.get().then((snapshot) => {
if (snapshot.data() == undefined) {
console.log(`${houseForGym}-${doc.data().name}: CREAR!!`);
} else if (snapshot.data()!.issued == false) {
let detail: { [key: string]: any} = {};
const GYMdetail: { [key: string]: number} = {};
detail = snapshot.data()!.detail;
GYMdetail[
`${doc.data().name} (${doc.data().personalID})`
] = 650;
const subtotal = 650 * GYMdetail.size;
detail["GYM"] = {"total": subtotal, "detail": GYMdetail};
snapshot.ref.set({"detail": detail}, {merge: true});
}
return null;
})
.catch((error) => {
console.log(
`${houseForGym} - ${doc.data().name}: ${error}`);
response.status(500).send(error);
return null;
});
}
});
response.send("i");
})
.catch((error) => {
console.log(error);
response.status(500).send(error);
});
});
Since you are executing an asynchronous call to the database in your code, you need to return a promise from the top-level code; otherwise Cloud Functions may kill the container when the final } executes and by that time the database load won't be done yet.
So:
export const addGymMonthlyExpense =
functions.https.onRequest((request, response) => {
const query1 = admin.firestore().collection("users");
const query = query1.where("subscriptions.gym.active", "==", true);
return query.get()
...
Next you'll need to ensure that all the nested get() calls also get a chance to finish before the Functions container gets terminated. For that I recommend not using await for each nested get call, but a single Promise.all for all of them:
query.get()
.then(async (allUsers) => {
const promises = [];
allUsers.docs.forEach((doc) => {
const houseForGym = doc.data().subscriptions.gym.house;
promises.push(admin.firestore()
.doc(`houses/${houseForGym}/expenses/2022-04`)
.get().then((snapshot) => {
...
});
});
response.send("i");
return Promise.all(promises);
})
.catch((error) => {
console.log(error);
response.status(500).send(error);
});

Strange Promise.all behaviour

In one file called SearchBuilder.js i have this function ( wrote in this way as pure test )
self.validateInputs = async params => {
const validateDates = async () => {
const pick_up_date = moment(`${params.pick_up_date} ${params.pick_up_time}`),
drop_off_date = moment(`${params.drop_off_date} ${params.drop_off_date}`);
return true;
};
const validatePickUpId = async () => {
return true;
};
const validateDropOffId = async () => {
throw { 'code': 'NOT_FOUND'};
};
return Promise.all([
validateDates,
validatePickUpId,
validateDropOffId,
]);
};
In another file called searchEngine.js i have this:
self.run = async (type, search_inputs, account) => {
const searchBuilder = self.getSearchBuilder(type);
try {
const isValid = await searchBuilder.validateInputs(search_inputs);
console.log(isValid);
} catch (e) {
console.log('error input validation');
}
return search;
};
I erroneously thought that if any of the promises in Promise.all would fail, so my code will enter the catch block. Instead, even if the promise fails code inside the catch is never executed and inside isValid i get this.
[ [AsyncFunction: validateDates],
[AsyncFunction: validatePickUpId],
[AsyncFunction: validateDropOffId] ]

Returning a Promise in Node.js

I can't wrap my head around this.
Take the following three functions where a calls b, and b calls c:
const c = () => {
return new Promise( (resolve, reject) => {
setTimeout(() => {
resolve(new Date());
}, "1750");
});
};
const b = async () => {
const result = await c();
console.log("b(): %s", result);
return result;
};
const a = async () => {
const result = await b();
console.log("a(): %s",result);
return result;
};
console.log("Starting...");
const final_result = a();
console.log("Final Result: %s", final_result);
console.log("Ending...");
I expected b() to wait-for/get the result of the promise returned by c(), and pass the value to a(). However, it looks like the promise gets passed all the way up the call stack.
To get the behavior I want, I have to handle the promise in each function:
const c = () => {
return new Promise( (resolve, reject) => {
setTimeout(() => {
resolve(new Date());
}, "1750");
});
};
const b = async () => {
const result = await c();
console.log("b(): %s", result);
return result;
};
const a = async () => {
const result = await b();
console.log("a(): %s",result);
return result;
};
(async () => {
console.log("Starting...");
const final_result = await a();
console.log("Final Result: %s", final_result);
console.log("Ending...");
})()
Why can't I just get the result of the promise in one function and return that? And, if I can do it, how?

Why isn't my Async Await flow not showing the results expected?

Im using Async on getJsonProducts, and I'm awaiting before console.log(products) but it still prints undefined. I thought await, pauses until the promise has been resolved?
Why aren't the products visible?
async function getJsonProducts(){
let products;
await fs.readFile('./products.json','utf-8',async (err,data)=>{
if(err)
throw err;
let r = /\"\_id.*\,(?=\"info\")|(?<=hex.*\})\,\"\_+v.*\d/g
let d = await data.replace(r,'');
d = await d.split('\n');d.pop();
products = await d.map(s=>JSON.parse(s));
//console.log(products) prints here
})
await console.log(products); //prints undefined here?
}
const seedProducts = async () => {
await getJsonProducts();
}
seedProducts();
I know there's other ways to implement this but I want to understand why this isn't working.
absolutely you will get undefined because you combined between async-await and the callback, also this is not how async-await works,
if you want to use async await , you can follow my code
async function getJsonProducts() {
return new Promise((reoslve, reject) => {
fs.readFile('./products.json', 'utf-8', async (err, data) => {
if (err) reject(err)
let r = /\"\_id.*\,(?=\"info\")|(?<=hex.*\})\,\"\_+v.*\d/g
let d = data.replace(r, '');
d = d.split('\n');
d.pop();
const products = d.map(s => JSON.parse(s));
resolve(products)
})
})
}
const seedProducts = async () => {
const products = await getJsonProducts();
conosle.log(products); // you will get products
}
seedProducts();
function getFile(cb) {
fs.readFile('./products.json', 'utf-8', (err, data) => {
if (err)
throw err;
let r = /\"\_id.*\,(?=\"info\")|(?<=hex.*\})\,\"\_+v.*\d/g
let d = data.replace(r, '');
d = d.split('\n');
d.pop();
cb(d.map(s => JSON.parse(s)));
})
}
async function getJsonProducts() {
this.getFile(products => console.log(products));
}
const seedProducts = async () => {
await getJsonProducts();
}
seedProducts();

Resources