Function that analyzes the list of passed paths

Viewed 59

I need an asynchronous "getTypes" function that analyzes the list of passed paths and returns an array describing what is in each of the paths. Function should work well in any case. If an error occurs during the asynchronous operation, the value for this path is "null". I tried to write a function, but it doesn't work.

const getTypes = (arr) => {
  const prom = arr.reduce((acc, path) => (
    acc.then((data) => {
       return fs.stat(path).isFile() ? 'file' : 'directory';
     })
    .catch(() => null)
  ), Promise.resolve());
  return prom;
}

How it should work:

getTypes(['/etc', '/etc/hosts', '/undefined']).then(console.log);
// ['directory', 'file', null]

Don't know how to do it, can anyone help? plz

1 Answers

Approach 1

async function getTypes(arr) { // Mark the function as async
   return Promise.all(arr.map(async (path) => { // Promise.all will wait for all mapped calls to be resolved
      try {
          const stat = await fs.stat(path) // fs.stat is async
      } catch(e) {
          return null
      }
      return stat.isFile() ? 'file' : 'directory';
   }));
}

Approach 2: (Modifications to OP's code)

const getTypes = arr => {
  const prom = arr.reduce((acc, path) => {
    acc
      .then(data => {
        return Promise.all([fs.stat(path), Promise.resolve(data)]);
      })
      .then(([stat, data]) =>
        stat.isFile()
          ? [Promise.resolve(data.push("file")), false]
          : [Promise.resolve(data.push("directory")), false]
      )
      .catch(() => Promise.resolve([data, true])) // so the next `then` can have access to data
      .then([data, failed] => failed === true ? Promise.resolve(data.push(null)) : Promsie.resolve(data)
  }, Promise.resolve([]));
  return prom;
};

Approach 3: (not fault-tolerant. i.e. Promise.all will fail if an error is thrown in any of the async calls):

function getTypes(arr) {
  const deferreds = arr.map(fs.stat);
  return Promise.all(deferreds).then(stats =>
    stats.map(stat => (stat.isFile() ? "file" : "directory"))
  );
}

Approach 4: (Slightly modifying #3 to make it fault-tolerant)

const getFileType = stat => stat.isFile() ? 'file' : 'directory'
const getFileStat = path => fs.stat(path).then(getFileType).catch(() => null)
const getTypes = paths => Promise.all(paths.map(getFileStat))
Related