I have a list of data that I am sending to google cloud. My current code looks like this:
const teams = ['LFC', 'MUFC', 'CFC']; teams.forEach(team => { fetch({ url: URL, method: 'PUT', body: team }); })
This works with one team
but it is timing out if sending multiple files and the files are bigger. I am sending images over and not strings. To solve this I need to POST
the data one file by one, and wait for the previous POST
to complete before sending the subsequent one. Can anyone advise the best way of doing this?
Worth noting that I don’t have any control over the number of files that are uploaded.
Advertisement
Answer
Use a reduce
instead of forEach
, with .then()
.
The following will store the promise of the last fetch
in acc
(the accumulator parameter of reduce
), and appends the new fetch
inside of a then
listener, to ensure that the previous fetch
is finished:
const teams = ['LFC', 'MUFC', 'CFC']; teams.reduce((acc, team) => { return acc.then(() => { return fetch({ url: URL, method: 'PUT', body: team }); }) }, Promise.resolve()) .then(() => console.log("Everything's finished")) .catch(err => console.error("Something failed:", err))
//Simulate fetch: const fetch = team => new Promise(rs => setTimeout(() => {rs();console.log(team)}, 1000)) const teams = ['LFC', 'MUFC', 'CFC']; teams.reduce((acc, team) => { return acc.then(() => { return fetch({ url: URL, method: 'PUT', body: team }); }) }, Promise.resolve()) .then(() => console.log("Everything's finished")) .catch(err => console.error("Something failed:", err))
You can even write a general helper function for it:
const teams = ['LFC', 'MUFC', 'CFC']; const promiseSeries = (arr, cb) => arr.reduce((acc, elem) => acc.then(() => cb(elem)), Promise.resolve()) promiseSeries(teams, (team) => { return fetch({ url: URL, method: 'PUT', body: team }) }) .then(() => console.log("Everything's finished")) .catch(err => console.error("Something failed:", err))
//Simulate fetch: const fetch = team => new Promise(rs => setTimeout(() => {rs();console.log(team)}, 1000)) const teams = ['LFC', 'MUFC', 'CFC']; const promiseSeries = (arr, cb) => arr.reduce((acc, elem) => acc.then(() => cb(elem)), Promise.resolve()) promiseSeries(teams, (team) => { return fetch({ url: URL, method: 'PUT', body: team }) }) .then(() => console.log("Everything's finished")) .catch(err => console.error("Something failed:", err))
Or, even better, if you can (it’s ES2017), use async/await
(it’s more readable):
const teams = ['LFC', 'MUFC', 'CFC']; async function upload(teams){ for(const team of teams){ await fetch({ url: URL, method: 'PUT', body: team }); } } upload(teams) .then(() => console.log("Everything's finished")) .catch(err => console.error("Something failed:", err))
//Simulate fetch: const fetch = team => new Promise(rs => setTimeout(() => {rs();console.log(team)}, 1000)) const teams = ['LFC', 'MUFC', 'CFC']; async function upload(teams) { for (const team of teams) { await fetch({ url: URL, method: 'PUT', body: team }); } } upload(teams) .then(() => console.log("Everything's finished")) .catch(err => console.error("Something failed:", err))