I cant get the result out of a fulfilled Promise React - javascript

Hello everyone
My goal:
Get the result out of a Promise that is fullfilled to use the result in a other piece of code
the results that I get are:
Results
but the expected result is the [[PromiseResult]].
I tried other methods I found on here. but there was one problem I did get the result only to show up in the command.log but when I tried to assign it to a value it looked like it skipped right over the code. I know this sounds like a duplicate posts of a post of How to return the response from an asynchronous call? but I tried it and it didn't work for me.
the check boundries returns a Promise
function getData() {
setLoading(true);
ref.onSnapshot((querySnapshot) => {
const items = [];
querySnapshot.forEach((doc) => {
let itemurl = 'http://leafletjs.com/examples/custom-icons/leaf-green.png';
let item = doc.data()
console.log(checkBoundaries(doc.data().RawData))
itemurl = checkBoundaries(doc.data().RawData)
console.log( itemurl)
item.colorIcon = itemurl;
console.log(item)
items.push(item);
console.log(items)
});
setRuuviTag(items);
setLoading(false);
});
}
but i cant get item.colorIcon to become the promise result
it would help alot if anyone knew a fix for this
Update
async function checkBoundaries(rdata) {
let iconurl;
try {
const response = await PostRawData(rdata)
const data = response.data
if (22.00>data.temperature && data.temperature > 4.00) {
console.log('if')
iconurl = 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-blue.png'
}
else {
console.log('else')
iconurl = 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png'
}
} catch (err) {
console.error(err)
}
console.log(`this is the url ${iconurl}`)
return iconurl
// ...
}
I will now get the things i tried but wont work

Related

Function returning blank array in inspect element with inaccessible data inside

SCENARIO
So I am trying to do multiple API requests with different URLs, add all the responses to an array, then return the array and use it. My code:
const getData = (dataURLs) => {
let returnData = [];
for (let i = 0; i < dataURLs.length; i++) {
getFetch(dataURLs[i]).then((response) => {
returnData.push(response);
return response;
});
}
console.log(returnData[0]);
return returnData;
};
So this is the function that makes the requests, here is what the getFetch function is:
const getFetch = async (url) => {
return fetch(url)
.then((response) => {
if (!response.ok) {
// get error message from body or default to response status
const error = (response && response.message) || response.status;
return error;
}
return response.json();
})
.catch((error) => {
return error;
});
};
This just makes the request and returns the JSON which is what I want, and this function works as I use it in other places.
PROBLEM
My issue is, when i make the request using the getData function, it will return a blank array '[]', however when I click on this array in inspect element, it displays this.
[] ->
0: {nodes: Array(5), edges: Array(5), self: Array(1)}
length: 1
If I try to access anything in this array in js it just doesn't let me. But if I look at it in Inspect Element, it will be a blank array that I can expand and it displays the requested data inside it
Just wondering if anyone knew a fix to this?
Thanks :)
The issue you're running into here is that the function returns the array before the promises have resolved (and put the data that you want into the arrays). You will need to wait for the promises first. There are a few ways you can do this, but one way is to put the promises into the array and use a Promise.all() to get all of the values when they are available.
const getData = (dataURLs) => {
let returnPromises = [];
for (let i = 0; i < dataURLs.length; i++) {
returnPromises.push(getFetch(dataURLs[i]));
}
return Promise.all(returnPromises);
};
From here on you will continue to use this function's result as a promise.
getData([...]).then(([result1, result2, ...resultN]) => {...})

How to iterate a JSON array and add data from an async arrow function?

I'm new on MEAN stack and also on JS. What I'm trying to accomplish is to adapt the response that I get from the DB adding to it another field.
I have a mongoose method that gave me all the Courses that exist and I want to add to that information all the Inscriptions for each one. So I'm trying this:
exports.getAllCourses = async(req, res) => {
try {
const rawCourses = await Course.find();
const courses = await courseAdapter.apply(rawCourses)
await res.json({courses});
} catch (error) {
console.log(error);
res.status(500).send("Ocurrio un error imprevisto :/");
}
};
My courseAdapter
exports.apply = (courses) => {
return courses.map(async course=> (
{
...course._doc,
number: await coursetUtils.getNumberOfInscriptions(course._doc._id)
}
));
}
And my courseUtils:
exports.getNumberOfInscriptions = async courseId => {
return await CourseInscription.countDocuments({courseId: courseId});
}
I think my problem is with the async-await function because with this code i get this:
{"courses":[
{},
{}
]}
or changing some stuff i get this:
{"courses":[
{"courseInfo":{...},
"number":{}
},
{"courseInfo":{...},
"number":{}
}
]}
But never the number of inscription on the response. By the way i use function getNumberOfInscriptions() in other part of my code for make a validation and works.
Trying a lot of stuff i get to this:
I change the way I process the data from DB in the apply function and I treat it like an array.
exports.apply = async (courses) => {
var response = [];
for (let c of courses) {
var doc = c._doc;
var tmp = [{course: doc, inscriptionNumber: await courseUtils.getNumberOfInscriptions(c._doc._id)}];
response = response.concat(tmp);
}
return response;
}
I think is not a pretty good way to accomplish my goal, but it works. If I find something better, performance or clean I will posted.
Anyways I still don't know what I was doing wrong on my previous map function when I call my async-await function. If anybody knows, please let me know.

Modify external object in promise function

I have an array of objects (books) that are missing some fields, so I'm using node-isbn module to fetch the missing data. However, I'm having trouble persisting the updates to the objects. Here's some example code:
const isbn = require('node-isbn');
var books = []; // assume this is filled in elsewhere
books.forEach(function(item) {
if (item.publication_year == '' ||
item.num_pages == '') {
isbn.provider(['openlibrary', 'google'])
.resolve(item.isbn)
.then(function (book) {
item.num_pages = book.pageCount;
item.publication_year = book.publishedDate.replace( /^\D+/g, '');
}).catch(function (err) {
console.log('Book not found', err);
});
}
console.log(item)
});
However, the console log shows that the num_pages and publication_year fields are still empty. How can I fix this?
Try not to use Promise inside forEach
Put your console.log inside the then block , it will print the result for you.You are doing a asynchronous operation by resolving promise so it will take some time for the data to come back , however since your console.log is outside of that promise , that will get executed first.
So if you want to see those values, you should put your console.log inside your then block.
However, You can use await and for of syntax to achieve the result
for await (item of books) {
if (item.publication_year == '' || item.num_pages == '') {
const book = await isbn.provider(['openlibrary', 'google'])
.resolve(item.isbn);
item.num_pages = book.pageCount;
item.publication_year = book.publishedDate.replace( /^\D+/g,'');
}
console.log(item)
}
console.log(books)

Pushing elements into the array works only inside the loop

I got some data which I'm calling from API and I am using axios for that. When data is retrieved, I dump it inside of a function called "RefractorData()" just to organize it a bit, then I push it onto existing array. The problems is, my array gets populated inside forEach and I can console.log my data there, but once I exit the loop, my array is empty.
let matches: any = new Array();
const player = new Player();
data.forEach(
async (match: any) => {
try {
const result = await API.httpRequest(
`https://APILink.com/matches/${match.id}`,
false
);
if (!result) console.log("No match info");
const refractored = player.RefractorMatch(result.data);
matches.push({ match: refractored });
console.log(matches);
} catch (err) {
throw err;
}
}
);
console.log(matches);
Now the first console.log inside forEach is displaying data properly, second one after forEach shows empty array.
Managed to do it with Promise.all() and Array.prototype.map()
.
const player = new Player();
const matches = result.data;
const promises = matches.map(async (match: any) => {
const response: any = await API.httpRequest(
`https://API/matches/${match.id}`,
false
);
let data = response.data;
return {
data: player.RefractorMatch(data)
};
});
const response: any = await Promise.all(promises);
You must understand that async functions almost always run later, because they deppend on some external input like a http response, so, the second console.log is running before the first.
There a few ways to solve this. The ugliest but easiest to figure out is to create a external promise that you will resolve once all http requests are done.
let matches = [];
let promise = new Promise((resolve) => {
let complete = 0;
data.forEach((match: any) => {
API.httpRequest(...).then((result) => {
// Your logic here
matches.push(yourLogicResult);
complete++;
if (complete === data.length) {
resolve();
}
}
}
};
console.log(matches); // still logs empty array
promise.then(() => console.log(matches)); // now logs the right array
You can solve this using other methods, for example Promise.all().
One very helpful way to solve it is using RxJs Observables. See https://www.learnrxjs.io/
Hope I helped you!

Resolving Promises sequentially not working

I have a code to:
Read last three data from Firebase
Iterate each retrieved data
Push a Promise-returning function expression to an array of Promise to be processed sequentially later
Process said array sequentially
Code:
firebase.database().ref('someRef').limitToLast(3).on('value', snapshot => {
let promiseArray = [];
snapshot.forEach(e => {
promiseArray.push(() => {
firebase.storage().ref(e.key).getDownloadURL().then(url => {
//Do something with URL
//In this case, I print out the url to see the order of URL retrieved
//Unfortunately, the order was incorrect
return 'Resolved, please continue'; //Return something to resolve my Promise
});
});
});
let result = Promise.resolve([]);
promiseArray.forEach(promise => {
result = result.then(promise);
});
});
I think that it should already be correct. However, the result I want to get is wrong. What did I miss?
EDIT
I seem to have missed a point. In my Promise array, I want the first function to resolve the Promise it returns first before continuing to the second function.
You should use reduce. A very good example you will find here: https://decembersoft.com/posts/promises-in-serial-with-array-reduce/
forEach is a synchronous method. You can use map to create the array of promises and then use promise.all.
firebase.database().ref('someRef').limitToLast(3).on('value', snapshot => {
let promiseArray = [];
const promiseArray = snapshot.map(e => firebase.storage().ref(e.key).getDownloadURL());
Promise.all(promiseArray).then((resultArr) => {
// Do anything with your result array
});
}
For sequential execution of promises you can use async await.
firebase.database().ref('someRef').limitToLast(3).on('value', async (snapshot) => {
let promiseArray = [];
const promiseArray = snapshot.map(e => firebase.storage().ref(e.key).getDownloadURL());
let result;
for(let i = 0; i < promiseArray.length; i++) {
result = await promiseArray[i];
}
});
I figured it out: apparently, I forgot to my function is not returning a Promise. Because of that, when I'm chaining the thens, it's not waiting for my Promise to resolve first as it wasn't even returned in the first place. I'm basically returning a void, thus the functions continue without waiting for the previous Promise to resolve. Simply adding return fixes the problem:
firebase.database().ref('someRef').limitToLast(3).on('value', snapshot => {
let promiseArray = [];
snapshot.forEach(e => {
promiseArray.push(() => {
return firebase.storage().ref(e.key).getDownloadURL().then(url => { //Add return here
//Do something with URL
//In this case, I print out the url to see the order of URL retrieved
//Unfortunately, the order was incorrect
return 'Resolved, please continue'; //Return something to resolve my Promise
});
});
});
let result = Promise.resolve([]);
promiseArray.forEach(promise => {
result = result.then(promise);
});
});

Categories

Resources