Home > OS >  How to wait until multiple files are processed before calling finished function js
How to wait until multiple files are processed before calling finished function js

Time:10-18

The following function runs after a drag and drop operation of multiple files.

function getFilesInfo(ev){
    for (let i = 0; i < ev.dataTransfer.items.length; i  ) {
        if (ev.dataTransfer.items[i].kind === 'file') {
            let file = ev.dataTransfer.items[i].getAsFile();
            //getFileInfo adds string to DOM element
            //Note the promise usage ...
            file.arrayBuffer().then((data)=>getFileInfo(file.name,data));
        }
    }
}

I can't figure out how to call a function after all of the promises in this function finish.

Basically I want something like this, sequentially:

getFilesInfo(ev);
   //getFileInfo(<file1>);
   //getFileInfo(<file2>);
   //getFileInfo(<file3>);
   // etc.
//run only after all getFileInfo() calls have finished
processResults();

The tricky part is that reading the files generates a promise for each file that gets called when the file has been read into memory (part of the arrayBuffer() call). I can't figure out how to delay processResults because getFilesInfo finishes after all of the read calls have been triggered, not (from what I can tell), after the getFileInfo functions have finished.

It seems like perhaps I could somehow add all arrayBuffer calls to an array and then do some promise chaining (maybe?) but that seems awkward and I'm not even sure how I would do that.

CodePudding user response:

You can use Promise.all to wait for an array of promise to finish:

async function getFilesInfo(ev) {
  // create list of jobs
  const jobs = [];
  for (const item of ev.dataTransfer.items) {
    if (item.kind === 'file') {
      let file = item.getAsFile();
      jobs.push(file.arrayBuffer().then(data => {
        getFileInfo(file.name, data);
      }));
    }
  }
  // wait for all promise to fullfil
  await Promise.all(jobs);
}

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

CodePudding user response:

async function getFilesInfo(ev) {
  await Promise.all(ev.dataTransfer.items.map(async (i) => {
    const file = i.getAsFile();
    const data = await file.arrayBuffer();
    return getFileInfo(file.name, data);
  }));
}

await getFilesInfo(ev); // will be awaited until all the promises are resolved
processResults();

Let me know if that helps.

CodePudding user response:

You could do it that way:

function getFilesInfo(ev){
    return ev.dataTransfer.items.filter(item=>item.kind === 'file').map(item=>{
        let file = item.getAsFile();
        return file.arrayBuffer().then((data)=>getFileInfo(file.name,data));
    });
}

Promise.all(...getFilesInfo(ev)).then(_=>{
    processResults();
});

// or with async/await
(async ()=>{
    await Promise.all(...getFilesInfo(ev));
    processResults();
})()
  • Related