0

I'm using JSZip to access files inside a zip. In that .zip there is one file that I'm looking for and I need it's content. To get the content it seems to require an async function. Which is called multiple times in a for loop.

My problem is that when I find the correct file, I'm in an async function so trying to get the value from the main program tell me 'undefined'. But I can't continue my code inside that async function because it's called in a loop so I would end running my main program many times.

var fileToFind;

JSZip.forEach(function (relativePath, file){
    
    var fileAsStr = JSZip.file(relativePath).async("string"); //this is the way to get file content in JSZip
    
    const waitStr = async () => {
        fileAsStr = await fileAsStr;
        const anchorStr = "Some string which is in only one file";
        if(fileAsStr.indexOf(anchorStr) != -1){
            fileToFind = fileAsStr;
            console.log(fileToFind); //works ok
        }
    waitStr();
});

... //lot of stuff

console.log(fileToFind); //undefined
PaddleStroke
  • 63
  • 1
  • 6
  • It's not a loop, it's a `forEach` callback function. With an actual `for` loop it would work :-) – Bergi Sep 01 '21 at 13:46
  • You can refer to this page: [Zellwk - async await in loop](https://zellwk.com/blog/async-await-in-loops/). In short, `forEach` does not work well with async and Promises. – Bao Huynh Lam Sep 01 '21 at 13:47
  • @Bergi thanks! Do you know what syntax should I use for the for loop? I'm not familiar with foreach actually so I don't understand what is relativePath and file used here by JSZip. – PaddleStroke Sep 01 '21 at 14:21
  • @PaddleStroke Whoops, I was suggesting to look at the duplicate but that actually is about using the `forEach` *array* method, not `JSZip.forEach`. I think you need to start with `const files = [];`, then in the `forEach` callback push the `file` objects onto the array (ignoring `relativePath` - you can get the path later from the [`ZipObject`](https://stuk.github.io/jszip/documentation/api_zipobject.html) if you need it), then use `for (const file of files) { const fileAsStr = await file.async('string'); if … { fileToFind = file; break; } }`. – Bergi Sep 01 '21 at 17:24
  • Thanks I'll do that ! – PaddleStroke Sep 02 '21 at 19:25

1 Answers1

0

Why define a function in a loop? Instead you can have the function defined already and called in the loop.

var fileToFind;

const waitStr = async (fileAsStr) => {
    fileAsStr = await fileAsStr;
    const anchorStr = "Some string which is in only one file";
    if(fileAsStr.indexOf(anchorStr) != -1) {
        fileToFind = fileAsStr;
        console.log(fileToFind); //works ok
    }
}

JSZip.forEach(function (relativePath, file) {
    
    var fileAsStr = JSZip.file(relativePath).async("string");
    waitStr(fileAsStr);
});
// ...
Lakshaya U.
  • 1,089
  • 1
  • 5
  • 21
  • Okay but that does not solve the core problem, which is how I can use the data. As if I write my code in the async function it will be called many times by the loop. – PaddleStroke Sep 01 '21 at 14:52
  • Well, you can change your `waitStr` function to get what you want. `fileAsStr` will remain `undefined` as you never mentioned to assign a value to it in your code, did you? – Lakshaya U. Sep 01 '21 at 16:08