function cool() {
console.log("goober");
fetch("lines.json")
.then(res => res.json())
.then(json => {
const splash = document.getElementById("splash")
splash.innerHTML = json[Math.floor(Math.random() * json.length)];
splash.style.animationDuration = `${Math.round(splash.clientWidth / 200)}s`
}).catch(error => {
console.log(error);
});
}
setInterval(cool,Math.round(splash.clientWidth / 200));
I've been scratching my head as to why this doesn't work, though it's probably something obvious - and this does work when using a regular number in the setInterval, too, so I'm really lost.
Related
I'm doing my first ever react website and I need help to write an asynchronous JavaScript function.
Here I'm uploading the user input files to a firebase storage and then making a post request to the API to store the data on the database. However, since the firebase upload takes some time to upload the data to its storage, the API request happens before the upload finishes, therefore the data does not get uploaded to the db. Now I know I should use promises of async await keywords here, but I can't figure out how to. I'd appreciate if someone could help. Thanks in advance!
Here's the relevant code snippet:
const save = (items) => {
items.forEach((item) => {
const fileName = new Date().getTime() + item.label + item.file.name;
const uploadTask = storage.ref(`/items/${fileName}`).put(item.file);
uploadTask.on(
"state_changed",
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is" + progress + "% done.");
},
(err) => {
console.log(err)
},
() => {
storage.ref("items").child(fileName).getDownloadURL().then((url) => {
setSong((prev) => {
return { ...prev, [item.label]: url };
});
});
}
);
})
console.log(song)
axios.post("songs/create", song);
}
PS: Here, items is the array of input files from the user, each file is with a label and it is how the attributes are named on the json document.
setSong is a useState function. Here The JSON document already contains the other user inputs(which are not files), and the setSong method is used to append the firebase URLs of the files to it.
You have to wait for all files to get uploaded then you can call your API, in order to do that you should use Promise.all to wait to resolve all files :
const save = items => {
Promise.all(
items.map(item => {
return new Promise(resolve => {
const fileName = new Date().getTime() + item.label + item.file.name
const uploadTask = storage.ref(`/items/${fileName}`).put(item.file)
uploadTask.on(
'state_changed',
snapshot => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
console.log('Upload is' + progress + '% done.')
},
err => {
console.log(err)
},
() => {
storage
.ref('items')
.child(fileName)
.getDownloadURL()
.then(url => {
setSong(prev => {
return { ...prev, [item.label]: url }
})
resolve({[item.label]: url})
})
}
)
})
})
).then((res) => {
const song = {}
res.forEach(item => {
return {
...song,
...item
}
})
axios.post('songs/create', song)
})
}
Explanation
Functions and Async
Async/Await can be implemented wherever a function starts. Functions can be written in following forms:
function name(){};
function name() => {};
To write an async function, you would do the following:
async function name(){};
All of these functions are called functions though, to make functions run without calling them, we need to turn them into IIFE's, or Immediately Invoked Function Execution. If you want to create a function and execute it immediately you would surround the function in ()'s and end it with an ();.
(function () {})();
If we simplify this:
(() => {})();
Implementing async would go like this:
(async () => {})();
Await
The await operator is used to wait for a Promise, puting await in front of an expression that uses promises makes it wait for the promise. If it is used in front of an expression that doesn't use promises, it is redundant and your code editor/IDE will say so.
(async () => {
const str = await 'some string';
console.log(str);
})();
await is redundant here since the expression 'some string' does not relate to a promise, but a string.
(async () => {
const myPromise = new Promise((resolve, reject) =>
resolve('some string')
);
const str = await myPromise.then(x => console.log(x));
})();
await is properly used here since the expression myPromise is related to a promise that outputs a string.
Implementation
I'm not 100% sure how the api works within promises, I recommend you figure it out yourself, but this is my educated guess:
const save = (items) => {
Promise.all(
items.map((item) => {
return new Promise(async (resolve) => {
const fileName = new Date().getTime() + item.label + item.file.name;
const uploadTask = await storage
.ref(`/items/${fileName}`)
.put(item.file);
await uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is" + progress + "% done.");
},
(err) => {
console.log(err);
},
async () => {
await storage
.ref("items")
.child(fileName)
.getDownloadURL()
.then((url) => {
setSong((prev) => {
return { ...prev, [item.label]: url };
});
resolve({ [item.label]: url });
});
}
);
});
})
).then(async (res) => {
const song = {};
res.forEach((item) => {
return {
...song,
...item,
};
});
await axios.post("songs/create", song);
});
};
hey guys i dont know why my setPlaceId works but not my setPlaceName
placeName doesnt print anything when there is some data that should be printed out could someone help? So yea i added more code, if you need more things ill post it, thanks for everyones help in advance i wish i can fix this as soon as possible.
tldr: setPlaceId pastes text but setPlaceName doesnt paste text when there are info that should be pasted.
btw i deleted some stuff from the code so it wouldnt be so long so dont worry about me not having some stuff that i called
function ConvertPlaces() {
const [placeName, setPlaceName] = useState("");
const [placeId, setPlaceId] = useState("");
useEffect(() => {
convert();
}, []);
const convert = () => {
fetch(
`https://skyscanner-skyscanner-flight-search-v1.p.rapidapi.com/apiservices/autosuggest/v1.0/UK/GBP/en-GB/?query=${userInput}`,
{
method: "GET",
headers: {
//deleted api keys
},
}
)
.then((res) => res.json())
.then((response) => {
console.log(response);
setPlaceName(response.Places.map((airport) => airport.PlaceName));
setPlaceId(response.Places.map((airport) => airport.PlaceId));
})
.catch((err) => {
console.log(err);
});
};
const handleChange = (event) => {
setInputField(event.target.value);
setUserInput(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
setSavedInput(inputField);
setInputField("");
convert();
};
return (
<div>
<SearchPlaces
run={convert}
handleChange={handleChange}
handleSubmit={handleSubmit}
inputField={inputField}
userInput={userInput}
savedInput={savedInput}
/>
<p>sfdajfp</p>
<p>{placeId}</p>
<p>{placeName}</p>
</div>
);
}
export default ConvertPlaces;
I am not sure this is going to solve your issue, as you should really show a little bit more code but, regardless of that, may I suggest you loop through the response only once?
// ...
fetch([API endpoint])
.then(res => res.json())
.then(response => {
const setPlaceData = response.reduce((outObj, airport) => {
outObj.PlaceNames.push(airport.PlaceName);
outObj.PlaceIds.push(airport.PlaceId);
return outObj;
}, { PlaceNames: [], PlaceIds: [] });
/*
* I am assuming that you are using 'useState()' hook and
* you are willingly replacing whatever content is already
* present in your state variables rather than adding to it.
* E.g.
* setPlaceName([...placeName, ...setPlaceData.PlaceNames]);
*/
setPlaceName(setPlaceData.PlaceNames);
setPlaceId(setPlaceData.PlaceIds);
});
// ...
i am newbie on this.
My problem is when I tried to return array full of values, it returned empty.
I faced some weeks before and I solved it, declaring the map as a const and returning its value in a function... but I can't remeber how I did it.
This is my code:
module.exports.deleteLockedEmail = (req, res, next) => {
const maxDateAd = new Date().getTime() - 2592000000;
const adIdsToDelete = [];
Admin.find({})
.then(emailLocked => {
const mapToLockedEm = emailLocked.map(element => {
return User.findOne({email:element.email})
.then(userLocked => {
return adIdsToDelete.push(userLocked)
})
.catch(error => console.log(error))
})
return mapToLockedEm
})
.catch(error => console.log(error))
cron.schedule("* * * * *", function() {
console.log("running a task every minute => delete locked ads");
});
}
How can I fill this array?
adIdsToDelete = [];
Remember that all these calls to database are asynchronous. To get the values you have to wait till the promise is resolved and return values. In this case we can wait for all Promises with Promise.all to be executed and after that in next then context
module.exports.deleteLockedEmail = (req, res, next) => {
const maxDateAd = new Date().getTime() - 2592000000;
const adIdsToDelete = [];
Admin.find({})
.then(emailLocked => {
const mapToLockedEm = emailLocked.map(element => {
return User.findOne({email:element.email})
.then(userLocked => {
return adIdsToDelete.push(userLocked)
})
.catch(error => console.log(error))
})
return Promise.all(mapToLockedEm)
}).then(() => {
// In this context the adIdsToDelete will be filled
});
.catch(error => console.log(error))
cron.schedule("* * * * *", function() {
console.log("running a task every minute => delete locked ads");
});
}
Also in general it can be a little tricky to work with variables like adIdsToDelete as they are in different scope than your promise chain. As it happened in your example - it can be confusing when this variable actually fills with values.
You can rewrite it as following
module.exports.deleteLockedEmail = (req, res, next) => {
const maxDateAd = new Date().getTime() - 2592000000;
Admin.find({})
.then(emailLocked => {
const mapToLockedEm = emailLocked.map(element => {
return User.findOne({email:element.email})
.catch(error => console.log(error))
})
return Promise.all(mapToLockedEm)
}).then(adIdsToDelete => {
// In this context the adIdsToDelete will be filled
});
.catch(error => console.log(error))
cron.schedule("* * * * *", function() {
console.log("running a task every minute => delete locked ads");
});
}
I have the below code, where I have to get data from all the files in the same DB. Node.js is running at the backend. When I try the below code, I always get the last fetch, can anyone please help me how to fix this.
The below is from the react JS frontend.
componentDidMount() {
console.log("This Worked Sucessfully")
this.getDataFromDb();
if (!this.state.intervalIsSet) {
let interval = setInterval(this.getDataFromDb, 1000);
this.setState({ intervalIsSet: interval });
}
}
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/passed')
.then(data => data.json())
.then(res => this.setState({ passed: res.data }));
};
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/failed')
.then(data => data.json())
.then(res => this.setState({ failed: res.data }));
};
getDataFromDb = () => {fetch('http://172.24.78.202:3001/api/all')
.then(data => data.json())
.then(res => this.setState({ data2: res.data }));
};
render() {
const primaryColor = getColor('primary');
const secondaryColor = getColor('secondary');
const { passed, failed, data2 } = this.state
From what I see by your code, you seem to be re-writing your goGetDataFromDB two times. Try changing the names of each function or, the way you call them. You can also take advantage of Promise.all to group the results of each call into a single return handle.
Check this link for the documentation of Promise.all
You could refactor your current code to something like this:
class MyComponent extends React.Component {
componentDidMount() {
this.getDataFromDb();
if (!this.state.intervalIsSet) {
let interval = setInterval(this.getDataFromDb, 1000)
this.setState({intervalIsSet: true })
}
}
getDataFromDb = () => {
Promise.all([
'http://172.24.78.202:3001/api/passed',
'http://172.24.78.202:3001/api/failed',
'http://172.24.78.202:3001/api/all'
].map(url => (
fetch(url)
.then(data => data.json())
.then(res => res.data)
)
)).then(([passed, failed, data2]) =>
this.setState({ passed, failed, data2 })
);
}
render() {
//...
}
}
I tried to keep as much as your code as possible so you could notice the differences.
I hope this helps.
In my Ionic 2 project I am downloading data from server every 1 minute in a provider class, and whenever the new data comes I need to refresh a chart in my page class, how can I use observables to achieve that?
This is how the code looks like in simplified version:
let startTime = new Date(Math.ceil(new Date().getTime() / 60000) * 60000);
this.Source = Rx.Observable.timer(startTime, 60000).timeInterval().pluck('interval');
this.Subscription = this.Source
.subscribe(data => {
this.http.post(this.ConnectionString)
.map(res => res.json())
.subscribe(data => {
//code
});
});
You can try like this using Observable.interval
//Time in milleseconds
Observable.interval(15000).flatMap(x => this.http.post(this.ConnectionString))
.map(res => res.json())
.subscribe(data => {
//code
});