I have to fetch about 30 files with ES6, each of them consists of 100 MB lines of text.
I parse the text, line by line, counting some data points. The result is a small array like
[{"2014":34,"2015":34,"2016":34,"2017":34,"2018":12}]
I'm running into memory problems while parsing the files (Chrome simply crashes the debugger), probably because I am parsing them all with map:
return Promise.all(filenamesArray.map( /*fetch each file in filenamesArray */ )).
then(() => { /*parse them all */ })
I'm not posting the full code because I know it's wrong anyway. What I would like to do is
- Load a single file with fetch
- Parse its text with a result array such as above
- Return the result array and store it somewhere until every file has been parsed
- Give the js engine / gc enough time to clear the text from step 1 from memory
- Load the next file (continue with 1, but only after step 1-4 are finished!).
but I can't seem to find a solution for that. Could anyone show me an example? I don't care if its promises, callback functions, async/await...as long as each file is parsed completely before the next one is started.
EDIT 2020825
Sorry for my late update, I only came around fixing my problem now. While I appreciate Josh Linds answer, I realized that I still have a problem with the async nature of fetch which I apparently did not describe well enough: How do I deal with promises to make sure one file is finished and its memory may be released? I implemented Joshs solution with Promises.all, only to discover that this would still load all files first and then start processing them. Luckily, I found another SO question with almost the same problem:
Resolve promises one after another (i.e. in sequence)?
and so I learned about async functions. In order to use them with fetch, this question helped me:
How to use fetch with async/await?
So my final code looks like this:
//returns a promise resolving with an array of all processed files
loadAndCountFiles(filenamesArray) {
async function readFiles(filenamesArray) {
let resultArray = [];
for (const filename of filenamesArray) {
const response = await fetch(filename);
const text = await response.text();
//process the text and return a much smaller extract
const yearCountObject = processText(text);
resultArray.push({
filename: filename,
yearCountObject: yearCountObject
});
console.log("processed file " + filename);
}
return resultArray;
}
return new Promise(
(resolve, reject) => {
console.log("starting filecount...");
readFiles(filenamesArray)
.then(resultArray => {
console.log("done: " + resultArray);
resolve(resultArray);
})
.catch((error) => {
reject(error);
})
}
);
}
Now every file is fetched and processed before the next.