Miha Šušteršič Miha Šušteršič - 19 days ago 8
Javascript Question

bluebird - function returns promise objects instead of actual data

Following this snippet I am trying to write a function that loops trough a directory, finds directories, and reads xml file names from those directories (I know that the folder structure will always remain the same). So far my function is working as expected, but when I try to get the return from the function I just get Promise objects.

My code:

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
const path = require('path');

function getFileNames(rootPath) {
// Read content of path
return fs.readdirAsync(rootPath)
// For every file in path
.then(function(directories) {
// Filter out the directories
return directories.filter(function(file) {
return fs.statSync(path.join(rootPath, file)).isDirectory();
});
})
// For every directory
.then(function(directories) {
return directories.map(function(directory) {
// Read file in the directory
return fs.readdirAsync(path.join(rootPath, directory))
.filter(function(file) {
return path.extname(file) == '.XML';
})
.then(function(files) {
// Do something with the files
return files;
});
});
});
}

getFileNames('./XML').then(function(files) {
console.log(files);
});


When I
console.log(files)
inside the last
.then
function inside
getFileNames
, I get the actual arrays of file names in the console. But when I run the code above I get this output:

[ Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined },
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined },
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined },
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined },
Promise {
_bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_promise0: undefined,
_receiver0: undefined } ]


Why is this happening and how to fix it?

Answer

In the lines

.then(function(directories) {
  return directories.map(function(directory) {
    return fs.readdirAsync…

you are creating a promise for an array of promises, and that's exactly what you're getting in your final log. Instead of returning an array of promises, you need to return a promise for an array of values - and Promise.all is exactly what does that:

.then(function(directories) {
  return Promise.all(directories.map(function(directory) {
    return fs.readdirAsync(…)
    …
  }));
})

However, in Bluebird it would be more idiomatic to use Promise.map(directories, function(…) { … }) or even the map method (similar to how you already used .filter did on the files in each directory):

function getFileNames(rootPath) {
  return fs.readdirAsync(rootPath)
  .filter(function(file) {
    return fs.statAsync(path.join(rootPath, file)).then(function(s) {
      return s.isDirectory();
    });
  })
  .map(function(directory) {
//^^^^
    return fs.readdirAsync(path.join(rootPath, directory))
    .filter(function(file) {
      return path.extname(file) == '.XML';
    })
    .map(function(file) {
      // Do something with every file
      return file;
    });
  });
}