Search code examples
javascriptnode.jsbluebird

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?


Solution

  • 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;
        });
      });
    }