Search code examples
javascriptvue.jsasync-awaitpromisejszip

JSZip VUE how to resolve a promise array and save to local variable


Haven't worked with async functions so i'm kind of lost here... What I'm trying to accomplish is to iterate through files in folder that is within a zip file with JSZip, save these files in an array and then sort them, save them to a local variable so I can send them further.

Here is my code where I get an array of promises:

async extractTests(file){
  let Zip = new JSZip();
  let tests = await Zip.loadAsync(file).then((zip) => {
      const promises = [];
      zip.folder("tests").forEach(async function (relativePath, file) {
        promises.push({ name: relativePath, data: await zip.file("tests/" + relativePath).async("text") });
      });
      return promises;
    })
  return tests;
}

Then I'm trying to sort the array in the event function which runs when a zip file is added:

extract(event) {
  const file = event.target.files[0];
  let res = this.extractTests(file);
  res.then(function (r) {
    res.sort(function (a, b) {
      var nameA = a.name.toUpperCase();
      var nameB = b.name.toUpperCase();
      console.log(a.name);
      if (nameA < nameB) {
        return -1;
      }
      else {
        return 1;
      }
    });
  })
}

The list needs to be sorted because it gets resolved in the wrong order - as far as I've gathered is that the sort function doesn't even fire - pretty sure it's something to do with a asynchronous function. The sort would work on local variable and it would be much simpler for me to save the array as a local variable - so how could I do that and resolve the promises.

Thanks in advance


Solution

  • Using async / await on higher-order function is highly discouraged and may lead un-predictable behavior where your code may seem to work but actually only triggers some asynchronous calls without providing the desired output.

    I cannot reproduce the issue for sure without having the archive structure with the same library, but you can try to change your extraction function as follows:

    async function extractTests(file: any) {
      let Zip = new JSZip();
      let tests = await Zip.loadAsync(file)
        .then((zip) => {
          const promises = [];
          zip.folder("tests")
            .forEach(function (relativePath, file) { // removed async function
              promises.push(
                zip.file("tests/" + relativePath)
                  .async("text")
                  .then((data) => { // replaced with Promise fulfillment data update
                    return { name: relativePath, data: data }
                  })
              );
            });
          return promises;
        })
      return Promise.all(tests); // Resolve all promises in parallel
    }