1

I'm building an app where I need to get metadata from files and I do that with "music-metadata" from npm but I need to get it for an array of files. The module returns promises, so I need to await them / use .then() but when I use await it doesn't await it, it just returns an array of empty objects and when I use .then() it returns one object with metadata not the array. I've only gotten it to work with a for/in loop:

const getMetadata = async (dirPath, fileName) => {
    return new Promise((resolve, reject) => {
        if (typeof dirPath !== "string") {
            reject(new Error("directory path must be given as String!"));
        }
        if (typeof fileName !== "string") {
            reject(new Error("file name must be given as String!"));
        }

        mm
        .parseFile(`${dirPath}/${fileName}`)
        .then(metadata =>
            resolve({ directory: dirPath, fileName: fileName, ...metadata })
        )
        .catch(err => reject(err));
    });
};

let musicMetadata = [];
for (const file in musicFiles) {
    try {
        musicMetadata.push(await getMetadata(directoryPath, musicFiles[file]));
    } catch (err) {
        console.error(err);
    }
}

But is there any way of doing it more "functional programming" like, similar to this:

const getMetadata = (dirPath: string, fileName: string): Promise => {
  return new Promise((resolve, reject) => {
    mm.parseFile(`${dirPath}/${fileName}`)
      .then(metadata =>
        resolve({ directory: dirPath, file: fileName, ...metadata })
      )
      .catch(err => reject(err));
  });
};

const musicMetadata = await musicFiles.map(async (file: string) => {
  return new Promise((resolve, reject) => {
    getMetadata(directoryPath, file)
      .then(metadata => resolve(metadata))
      .catch(err => reject(err));
  });
});

TIA for any replies!

stuchlyf
  • 187
  • 1
  • 2
  • 11

2 Answers2

2

Consider using Promise.all on your collection of promises. It'll resolve with an array of resolved promises when they are all done. If a single one rejects, it'll return the that one rejection.

let doSomeTask = (msecs)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{return resolve('I waited ' + msecs)}, msecs);
    });
}

var promises = [
    doSomeTask(2000),
    doSomeTask(1500),
    doSomeTask(3000)
];

Promise.all(promises).then((resolved,rejected)=>{
    console.log(resolved); // Array(3) [ "I waited 2000", "I waited 1500", "I waited 3000" ]
});
Gavin
  • 2,214
  • 2
  • 18
  • 26
1

One way I've found to be able to do is like this:

const musicMetadata = await Promise.all(
  musicFiles.map(async file => {
    return await getMetadata(directoryPath, file);
  }
);

Hope this helps :)

Miika
  • 402
  • 4
  • 13