How to wait data from fetching json file and then continue - javascript

I am new in JavaScript and I have a problem:
I do fetch('path'), then I assign values and return it. Later I call this function in my other functions but it runs first with empty values without waiting values to be assigned. How can I solve this? I think I should use async and await but do not know exactly how.
function loadLocalJson(path) {
let users = [];
fetch(path)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok :(');
}
return response.json();
})
.then(results => {
users = results
console.log(users);
})
.catch(err => console.log('Error', err));
return users;
}
function getFilteredAndSortedArray(users, price) {
console.log(users, price);
return users.filter(user => {
return user.salary && user.salary > price;
})
.sort(user => user.name);
}
users = loadLocalJson('users.json');
usersB= getFilteredAndSortedArray(users, 1000);
console.log(usersB, usersA);
// PrefixedUsersArray(users)
// ...

You need to understand how asynchronous code works. A fetch request returns a promise, so you must return the promise and access the value using .then():
function loadLocalJson(path) {
return fetch(path)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok :(');
}
return response.json();
})
.catch(err => console.log('Error', err))
}
function getFilteredAndSortedArray(users, price) {
console.log(users, price);
return users.filter(user => {
return user.salary && user.salary > price;
}).sort(user => user.name);
}
loadLocalJson('users.json').then(users => {
usersB = getFilteredAndSortedArray(users, 1000);
console.log(usersB, users);
})
You do not have to assign users, you can just return the promise, sinc eyou have already called response.json(). Also, your sort function most likely won't work, try something like this:
users.sort((a, b) => a.name.localeCompare(b.name))

Related

Fetch in fetch inside a loop JS

The question is, how can I get rid of calling second fetch 300 times? Or is there another way to do that, what I`m doing?
Additionally how to do ordered(don`t wanna sort) calls of first api, because they`re coming from api in chaotic asynchronous way?
for(let i=1;i<=300; i++) {
fetch(`example.api/incomes/${i}`) // should be returned 300 times
.then(response => {
if(response.ok) return response.json();
throw new Error(response.statusText);
})
.then(function handleData(data) {
return fetch('example.api') // should be returned 1 time
.then(response => {
if(response.ok) return response.json();
throw new Error(response.statusText);
})
})
.catch(function handleError(error) {
console.log("Error" +error);
});
};
You can solve it using Promise all.
let promises = [];
for (let i = 1; i <= 300; i++) {
promises.push(fetch(`example.api/incomes/${i}`));
}
Promise.all(promises)
.then(function handleData(data) {
return fetch("example.api") // should be returned 1 time
.then(response => {
if (response.ok) return response.json();
throw new Error(response.statusText);
});
})
.catch(function handleError(error) {
console.log("Error" + error);
});
Store all of your requests in an array. Then use Promise.all() the wait for all of those requests to finish. Then when all of the requests are finished, use another Promise.all() with a map() inside of it to return the the JSON of each request and wait for all of those to finish.
Now your data argument will have an array of objects available in the next then callback.
function fetch300Times() {
let responses = [];
for(let i = 1; i <= 300; i++) {.
let response = fetch(`example.api/incomes/${i}`);
responses.push(response);
}
return Promise.all(responses);
}
const awaitJson = (response) => Promise.all(responses.map(response => {
if(response.ok) return response.json();
throw new Error(response.statusText);
}));
fetch300Times()
.then(awaitJson)
.then(data => {
fetch('example.api') // should be returned 1 time
.then(response => {
if(response.ok) return response.json();
throw new Error(response.statusText);
});
}).catch(function handleError(error) {
console.log("Error" +error);
});

While using .fetch, can I chain together existing .fetch functions into a larger synchronous query?

I know how to chain all of this together into one function. I am confused on how I'd incorporate the following function's return value into another?
function queryPlayers() {
fetch("foo", apiParams)
.then(res => {
if(res.ok){ return res.json() }
else { return fetch("backup_bar", apiParams)
.then(res => { return res.json() }
)}
})
.then(playerData => { return playerData })
.catch(err => console.log(err))
}
All I want to do is take playerData, or the JSON I receive and throw it into another function as an argument once the promise resolves. I'm quite new to arrow functions and promises and I feel I just am missing something.
function getExtraData(playerData){
fetch("some_foo" + playerData)
.then(newData => doStuff())
}
For reference, here is what I ended up doing as a super basic answer to the question:
function queryPlayers() {
console.log("Querying players...");
return fetch("https://api-v2.royaleapi.com/top/players", apiParams)
.then(res => {
if(res.ok){ return res.json() }
else { return fetch("http://127.0.0.1:8000/js/players.json", apiParams)
.then(res => res.json()
)}
})
.then(playerData => {
return playerData;
})
.catch(err => console.log(err))
}
function queryData(){
queryPlayers()
.then(data => console.log(data))
}
$(function(){
queryData();
});

Code works from project but not from a Firestore Cloud Function

Update: Refactored the code at the end below to this:
let getMembersIDs = eventID => {
return admin.firestore().collection('events').doc(eventID).get()
.then(doc => {
if (doc.exists) {
console.log(doc.data().members)
return doc.data().members
}
else throw new Error ('Event does not exist!', doc.id)
})
}
let dispatchToMembers = (arrayMembersIDs, data) => {
return Promise.all(
arrayMembersIDs.map(memberID => {
if (data.at===memberID) data.type = 'pm'
else data.content = 'New message in an event chat you participate to.'
console.log('Sending now to: ', memberID)
return admin.firestore().collection('users').doc(memberID).collection('inbox').add({
content: 'You were mentioned in a recent chat: ' + data.content,
type: data.type
})
})
)
}
getMembersIDs(data.target).then(members => dispatchToMembers(members, data)).then(() => {
console.log('Message dispatched!')
res.end()
return true
})
.catch(err => {
console.error(err);
response.status(500).send(err);
return true;
})
})
It does work when I run it from my project, replacing admin.firestore() with db. However when embedded within a cloud function it does not work: the cloud function returns codes 204 and 200 but the desired db operation does not seem to occur. Pulling my hair as I don't understand why.
Outdate: I am not able to debug the following piece of code. A simple cloud function with two parts (a read, a write) chained with promises.
exports.discuss = functions.https.onCall((data, context) => {
return admin.firestore().collection('events').doc(data.target).get()
.then(doc => {
if (doc.exists) return doc.data().members
else throw new Error ('Doc does not exist ', doc.id)
})
.then(members => {
let promises = []
members.forEach(u => {
...
let promise = new Promise(res => {
admin.firestore().collection('users').doc(u).collection('inbox').add({...})
res(u)
})
promises.push(promise)
})
return Promise.all(promises)
})
.then(() => {
response.send('ok')
return;
})
.catch(err, response.status(500).send(err))
})
You generate that 500 code with this line:
.catch(err, response.status(500).send(err))
The client that invokes the Cloud Function should be getting the error message in the response body. But you'll also want to log it on the server with:
.catch(function(err) {
console.error(err);
response.status(500).send(err);
return true;
})

Javascript - How do I send my variable to my frontend from the promise I use to query the database?

This is the promise that I use. Im also using the node-mssql package.
const loadpictures = () => {
sql.connect(config).then(pool => {
return pool.request()
.query('SELECT Top 20 PhotoURL As src, PostURL As link from Valley_Photos FOR JSON PATH')
}).then((result) => {
//console.dir(result);
sql.close();
return result['result'].typeOf();
}).catch(err => {
console.log(err)
sql.close();
})
}
loadpictures()
.then(result => console.log(results))
.catch( err => ErrorHandler(err) );
The error I get is:
TypeError: Cannot read property 'then' of undefined
The console.dir outputs the desired json object. I just dont know how to pull it out.
What am I doing wrong?
You're not returning any promise from loadpictures function, therefore, you cannot use then statement in your main.
It's pretty easy to return the second promise that you are using with async/await :
const loadpictures = async () => {
let pool = await sql.connect(config);
let req = pool
.request()
.query('SELECT Top 20 PhotoURL As src, PostURL As link from Valley_Photos FOR JSON PATH')
req.then((result) => {
//console.dir(result);
sql.close();
return result['result'].typeOf();
}).catch(err => {
console.log(err)
sql.close();
})
return req;
}
loadpictures()
.then(result => console.log(results))
.catch( err => ErrorHandler(err) );
On the other side, using only promises is a bit more verbose because you have to return a new promise that resolves with result and rejects with err :
const loadpictures = () => {
return new Promise((resolve, reject) => {
sql.connect(config).then(pool => {
return pool.request()
.query('SELECT Top 20 PhotoURL As src, PostURL As link from Valley_Photos FOR JSON PATH')
}).then((result) => {
//console.dir(result);
sql.close();
resolve(result)
}).catch(err => {
console.log(err)
sql.close();
reject(err);
})
}
}
loadpictures()
.then(result => console.log(results))
.catch( err => ErrorHandler(err) );
then is undefined because you're not returning a promise from the function. If you didn't need to use sql.close() you could simply return sql from the function because its a function that returns a promise, but since you do, wrap the sql call in a promise and resolve/reject the results/errors.
function loadpictures() {
return new Promise((resolve, reject) => {
sql
.connect(config)
.then(pool => {
return pool.request().query(query)
})
.then(result => {
sql.close();
resolve(result['result'].typeOf());
})
.catch(err => {
sql.close();
reject(err);
});
});
}
loadpictures()
.then(result => console.log(result))
.catch(err => ErrorHandler(err));

Merge api request using promise

Due to the api of a plugin I'm using not working properly. I need to merge the two different requests. I am using the thunk below.
I can get a response but I cannot seem to check for response.ok, and return the combined data:
export function fetchCategories() {
const firstPage =
"http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page=1";
const secondPage =
"http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page=2";
return dispatch => {
dispatch(isLoading(true));
Promise.all([fetch(firstPage), fetch(secondPage)])
.then(response => {
// check for ok here
response.ForEach(response => {
if (!response.ok) throw Error(response.statusText);
});
dispatch(isLoading(false));
return response;
})
.then(response => response.json())
// dispatch combined data here
.then(data => dispatch(fetchSuccessCategories(data)))
.catch(() => dispatch(hasErrored(true)));
};
}
Any ideas?
You are doing the check for .ok fine because it's in a loop, but your response is actually an array of two Response objects, it does not have a .json() method. You could do Promise.all(responses.map(r => r.json())), but I would recommend to write a helper function that does the complete promise chaining for one request and then call that twice:
function fetchPage(num) {
const url = "http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page="+num;
return fetch(url).then(response => {
if (!response.ok)
throw new Error(response.statusText);
return response.json();
});
}
export function fetchCategories() {
return dispatch => {
dispatch(isLoading(true));
Promise.all([fetchPage(1), fetchPage(2)]).then(data => {
dispatch(isLoading(false));
dispatch(fetchSuccessCategories(merge(data)));
}, err => {
dispatch(isLoading(false));
dispatch(hasErrored(true));
});
};
}

Categories