How to call async Function until condition is true using javaScript? - javascript

I have such a problem, I am using API call which returns Fake store data, Everything works fine I am pushing received data into arr array, my aim is to call repeatCall() function until arr.length will be arr.length === 100, Also the problem is, sometimes I want to filter received data based on condition and then push it into arr array, What would be the optimal solution in this case?
let arr = [];
async function repeatCall() {
const req = await fetch(`https://fakestoreapi.com/products`);
const resp = await req.json();
arr.push(...resp)
console.log(arr.length)
}
repeatCall()

Use an if condition on arr.length it will fetch api till the length is equal to 100.
let arr = [];
async function repeatCall() {
const req = await fetch(`https://fakestoreapi.com/products`);
const resp = await req.json();
arr.push(...resp)
console.log(arr.length)
if(arr.length < 100){
repeatCall();
}
}
As for filtering the data before pushing it to array.
let arr = [];
async function repeatCall() {
const req = await fetch(`https://fakestoreapi.com/products`);
const resp = await req.json();
resp.foreach(item => {
if(condition){
arr.push(item);
}
else{
console.log("don't push")
}
})
if(arr.length < 100){
repeatCall();
}
console.log(arr.length)
}

Related

FetchAPI parallel API calls, making URL array with for loop doesn't work, manual array works. Can't understand why

I'm trying to form an url array to then perform parallel fetches usign .map and Promise.all
The code in itself works if I try it with a manually made array but not if I try to form an array (for pagination) with a for loop.
I get the maxnumber of pages from the headers of the first fetch and with that number I use a for loop to add an increasing numbered page until the final amount of pages.
I'm realizing trying to make a minimally reproducible example here that this isn't 'working' in a sense, when I do this in my server with this sample code, it works and
console.log(urls);
actually shows the looped urls and it does seem to be in array format, since I used push seems impossible not to be? But then again, when performing the urls.map it doesn't work at all and trying to do something else, like .slice to urls it doesn't work either, so I'm sensing I'm not forming the array I think I am?
I can't figure it out.
async function smt() {
var url = 'https://jsonplaceholder.typicode.com/todos/';
var urls = [];
var firstFetch = fetch(url)
.then(function(e) {
var maxpages = 5;
//var maxpages = e.get.headers('TotalPages'); < I would get the maxpages here
for (let i = 1; i < maxpages; i++) {
urls.push(url + i)
}
});
console.log(urls);
var data = await Promise.all(urls.map(async url => {
const res = await fetch(url);
return res.json();
}))
console.log(data);
var other = [
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3',
'https://jsonplaceholder.typicode.com/todos/4',
]
var data2 = await Promise.all(other.map(async url => {
const res = await fetch(url);
return res.json();
}))
console.log(data2);
}
smt();
The problem was with the .then() function I had no clue but I tested everypart until it worked.
async function smt() {
var url = 'https://jsonplaceholder.typicode.com/todos/';
var urls = [];
var firstFetch = await fetch(url)
var maxpages = 5;
//var maxpages = firstFetch.get.headers('TotalPages'); < I would get the maxpages here
for (let i = 1; i < maxpages; i++) {
urls.push(url + i)
}
console.log(urls);
var data = await Promise.all(urls.map(async url => {
const res = await fetch(url);
return res.json();
}))
console.log(data);
var other = [
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3',
'https://jsonplaceholder.typicode.com/todos/4',
]
var data2 = await Promise.all(other.map(async url => {
const res = await fetch(url);
return res.json();
}))
console.log(data2);
}
smt();
/**** Updated Answer ****/
async function smt() {
var url = 'https://jsonplaceholder.typicode.com/todos/';
var urls = [];
//var firstFetch = await fetch(url) < would get headers
var maxpages = 5;
//var maxpages = firstFetch.get.headers('TotalPages'); < I would get the maxpages here
for (let i = 1; i < maxpages; i++) {
urls.push(url + i)
}
console.log(urls);
let promises = urls.map(async url => {
let a = await fetch(url);
return a.json()
})
var data = await Promise.all(promises)
console.log(data);
}
smt();
I think this is a better approach since you can limit concurrency when you do the urls.map outside the Promise.all.
I have done it with p-limit in node it works great.
const limit = pLimit(8);
let promises = urls.map(url => {
return limit(async() => {
let a = await fetch(url, optionsGet)
return a.json()
})
});

unable to shuffle array correctly in react

I am trying to shuffle an array in react . I fetch the data from the api and then I want to mount the data pictures as a shuffled array in my screen and not in the order I fetched them .
This is my code :
useFetch.js
import {React , useState , useEffect} from 'react';
export default function useFetch() {
const [ pokemon,setPokemon] = useState([]);
const [shuffled,setShuffled]= useState([]);
useEffect(()=>{
const fetchPokemon = async () =>{ //here I fetch my pokemon
const promises = [];
for (let i=1;i<=10;i++){
let url = `https://pokeapi.co/api/v2/pokemon/${i}`;
let response = await fetch(url);
let result = await response.json();
promises.push(result);
}
const data = await Promise.all(promises);
setPokemon(...pokemon,data); //successfully sets the pokemon data
}
const shufflePokemon = ()=>{ //here I try to shuffle the pokemon array and return a random on mount
fetchPokemon();
let randomArray= pokemon.map((poke,index)=>{ //this is what I am trying to do to shuffle the array but it is not correct
let j = Math.floor(Math.random() * (index + 1));
let temp = poke[index];
poke[index] = poke[j];
poke[j] = temp;
})
setShuffled(...shuffled,randomArray);
}
shufflePokemon(); //call shuffle on mount
},[])
return {shuffled} //returns shuffled array of objects
}
In my code above in the shufflePokemon function I try to give an idea of what needs to be done but the code is obviously not correct . I would appreciate your help
You can shuffle the array as soon as you get responses from api.
useEffect(() => {
const shuffle = (array) => {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
};
const fetchPokemon = async () => {
//here I fetch my pokemon
const promises = [];
for (let i = 1; i <= 10; i++) {
let url = `https://pokeapi.co/api/v2/pokemon/${i}`;
let response = await fetch(url);
let result = await response.json();
promises.push(result);
}
const data = await Promise.all(promises);
shuffle(data);
setPokemon(data);
};
fetchPokemon();
}, []);
Fischer-Yates shuffle is usually what's used.
It looks like you're close, but the algorithm pulls a random item from the end of the array, not the beginning as you're doing.
const randomArray = Array.from(fetchPokemon()).forEach((v,i,a) => {
const r = a.length - 1 - Math.trunc(Math.random() * i);
[ a[i], a[r] ] = [ a[r], a[i] ];
});

JSON file make the 20 most played games appear on my front page

I have a JSON URL (https://api.rawg.io/api/games?page=3), and I'm trying to make a appear the name, picture, the slug and the platforms on my front page. I have a idea like sort the most played games and push there id's in a array. But I don't know how I can first sort their number of players and then conserve their id's in an array.
code:
let array = ['']
function sort(x){
var swapped = true;
while(swapped){
swapped = false;
for (let i = 0; i<x.length;i++){
if (x[i] > x[i+1]){
let newnmb = x[i+1];
x[i+1] = x[i];
x[i] = newnmb;
swapped = true;
}
}
}
}
for(page=1;page<=15;page++){
fetch('https://api.rawg.io/api/games?page='+page)
.then(response => {
return response.json()
})
.then(data => {
let i = 0
while(data.results[i]){
if(typeof data.results[i].added_by_status.playing == 'undefined'){
}
else{
array.push(data.results[i].added_by_status.playing);
}
i++
}
sort(array)
})
}
Your code would look like this:
// your result from the API
const resultObject = {};
let resultArray = [];
// transform JSON object to an array
Object.keys(resultObject).forEach((key, index) => {
resultArray.push(resultObject[key]);
});
// comparator
function sortByPlayerCount(firstEl, secondEl) {
return firstEl.added_by_status.playing - secondEl.added_by_status.playing;
}
// sort array by player count
resultArray.sort(sortByPlayerCount);
You should wait until all the pages are received, use async / await and wait for the result with then().
For sorting on playcount, use array.sort().
Small example, please see comments in the code
async function getGames(max = 10) {
// Temporary hold games
let games = [];
// For number of pages
for(let page=1;page<=max;page++) {
// Get API response
await fetch('https://api.rawg.io/api/games?page=' + page).then((response) => response.json()).then((data) => {
// For each game in the response
data.results.forEach((value) => {
// Push to tmp array
games.push(value);
})
});
}
// Return games
return games;
}
// Get and wait allGames
getGames().then((allGames) => {
// Sort games on playtime
allGames.sort((a,b) => (a.playtime < b.playtime) ? 1 : ((b.playtime < a.playtime) ? -1 : 0));
// Loop through best 10 games
for(let toShow=0;toShow<=20;toShow++) {
// Get game by for index
const tmpGame = allGames[toShow];
// Write some info to docuemnt
document.write(tmpGame.name + '---' + tmpGame.playtime + '<br>');
}
});

JavaScript Asynchronous in Redux..?

Action in fuction (action for data imported from firstore)
Here you get index data.
export async function getUserIndex (data){
let db = loadFB().firestore();
console.log(data)
let date = moment(data).utc().format()
let query = db.collection('users').where("create_date", ">", date)
console.log(query)
return await query.get().then(docs=>{
let result = docs.size
console.log("result!!", result)
return result
})
}
components in function
async getuserIndex_component(date){
let number =""
number = await userAction.getUserIndex(date)
console.log("number",number)
return await number
}
const {user_list} = this.props; //user_list = [{id:aa, pw:bb},{id:cc, pw:dd}...} data
let data = user_list
let groups = {}
let number =0
for (let index_data of data) {
let date = moment(index_data.create_date).format("YYYY-MM-DD").slice(0, 10)
let index = this.getuserIndex_component(date) //<==here log Promise{<pendding>}
console.log(index)
if (groups[date]) {
let group = groups[date];
group.push({ index: index-number, ...index_data });
} else {
number =0;
groups[date] = [{ index: index-number, ...index_data }]
}
number++;
}
const dates = Object.keys(groups)
const user_list_result = []
for (let date of dates) {
user_list_result.push(...(groups[date]))
}
return(...)
I am using redux. in action
Made a "getUserIndex()."
The component will then access the "getUserIndex" and retrieve data. But there is only pending in the console.log, and the data I want does not appear.
In this situation, I would like to know how to deal with async in for of.
I want to know what part I'm making a mistake.
In summary, functions in components are executed later than the render. So the index in the render does not contain the data. What is the solution to this?
As getuserIndex_component is asynchronous, it will return a promise. You will need to wait for that promise to resolve before the index result is available.
Firstly, you should be able to simplify getuserIndex_component to
async getuserIndex_component(date) {
let number = await userAction.getUserIndex(date)
console.log("number", number)
return number
}
And when you remove the console.log it could simply be
async getuserIndex_component(date) {
return userAction.getUserIndex(date)
}
As I mentioned in the comments. You can send off all of the async calls, then just wait for all of the promises to resolve via Promise.all.
Something like this. (I couldn't test any of this, but it should demonstrate the general idea.)
const { user_list } = this.props; //user_list = [{id:aa, pw:bb},{id:cc, pw:dd}...} data
let data = user_list
let groups = {}
let number = 0
const dates = []
const promises = data.map((index_data) => {
const date = moment(index_data.create_date).format("YYYY-MM-DD").slice(0, 10)
dates.push(date) // To use after all promises resolve.
return this.getuserIndex_component(date) // The index promise.
})
const indexes = await Promise.all(promises)
for (let i = 0; i < dates.length; i++) {
const index = indexes[i]
const date = dates[i]
console.log(index)
if (groups[date]) {
let group = groups[date];
group.push({
index: index - number,
...index_data
});
} else {
number = 0;
groups[date] = [{
index: index - number,
...index_data
}]
}
number++;
}
const dates = Object.keys(groups)
const user_list_result = []
for (let date of dates) {
user_list_result.push(...(groups[date]))
}
return (...)

scan duplicates item with DynamoDB

I'd like to scan items and avoid to use duplicates code.
so, I am trying to use for-of asynchronously for it.
async function checkDupl(){
const arr = new Array(10).fill(0);
let code = '';
for(const i of arr){
//generate RANDOM CODE
//for example, it would be '000001' to '000010'
code = (Math.floor(Math.random() * 10) + 1).toString().padStart(6,"0");
const params = { ... }; // it has filterExpression the code I generated randomly
await DYNAMO_DB.scan(params, (err, res) => {
if(res.Items.length === 0) {
/* no duplicate! */
return code;
}
});
}
return code;
}
console.log(checkDupl());
// it always return '';
What I have missed or misunderstood?
await just waits a Promise (or thenable object), but you are using await with a "void" function (You use DYNAMO_DB.scan as a callback styte function).
My suggestion, Use DYNAMO_DB.scan with Promise style (The way)
async function checkDupl() {
const arr = new Array(10).fill(0);
let code = '';
for (const i of arr) {
//generate RANDOM CODE
//for example, it would be '000001' to '000010'
code = (Math.floor(Math.random() * 10) + 1).toString().padStart(6, "0");
const params = { ... }; // it has filterExpression the code I generated randomly
const res = await DYNAMO_DB.scan(params).promise(); // convert to promise
if (res.Items.length === 0) {
/* no duplicate! */
return code;
}
return code;
}
}
(async () => {
console.log(await checkDupl());
})();

Categories