Search code examples
javascriptnode.jspromisebluebird

How (not) to nest `then` producing promise methods?


What is a clean way to use bluepird promisified fs methods? readdir will produce an array of files and folders, but if I in turn which to loop through the directories it provides, I end up writing something very similar to a callback nesting paradigm (except it doesn't even work). What is the standard practice chaining these promises in such a way that their return values may be looped through?

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs-extra'));
var path = require('path');
var junk = require('junk');

//this does not work
fs.readdirAsync('./node_modules')
  .bind(this)
  .then((modules) => {
    this.allFiles = [];
    modules = modules.filter((item) => junk.not && !/^\./.test(item)); 
    modules.forEach((module, index, modulesArray) => {
      fs.readdirAsync(path.join('node_modules', module)) //ugly af and don't even get files to next `then`!
        .then((files) => { 
          console.log(files); // yep, array of files all right
          this.allFiles.push(files);
        });
    })
  })
  .then(() => {
    console.log('all of the files', this.allFiles) // => [] no files 😞
  })
  .catch((err) => {
    console.error('error! error!', err);
  })

Solution

  • You aren't returning a promise in your first outer then. Therefore your outer promise chain doesn't wait for the files to be read.

    You can use Promise.all + map to do so. A second suggestion from me is to don't use this to store your values but pass all needed information through your promise chains. That makes the code much shorter:

    fs.readdirAsync('./node_modules')
      .then((modules) => {
        return Promise.all(modules.filter((item) => junk.not && !/^\./.test(item))
          .map(module => fs.readdirAsync(path.join('node_modules', module))));
      })
      .then(allFiles => {
        console.log('all of the files', allFiles);
      })
      .catch((err) => {
        console.error('error! error!', err);
      });