Javascript 读取多个目录中的文件,使用节点和承诺将文件名与其数据匹配

Javascript 读取多个目录中的文件,使用节点和承诺将文件名与其数据匹配,javascript,node.js,promise,fs,Javascript,Node.js,Promise,Fs,我有一个目录数组 var directories = ['/dir1', '/dir2']; 我想读取这些目录下的所有文件,最后有一个对象将文件名与其base64/utf8数据相匹配。在我的例子中,这些文件是图像。生成的对象可能如下所示: var result = { '/dir1': { 'file1': 'iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAIAAACx0UUtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWF...', 'fi

我有一个目录数组

var directories = ['/dir1', '/dir2'];
我想读取这些目录下的所有文件,最后有一个对象将文件名与其base64/utf8数据相匹配。在我的例子中,这些文件是图像。生成的对象可能如下所示:

var result = {
 '/dir1': {
  'file1': 'iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAIAAACx0UUtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWF...',
  'file2': 'iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAIAAACx0UUtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWF...'   
 }
}
我用一个回调地狱轻松实现了这一点,但当我尝试使用承诺时,我不确定如何将目录信息和文件名传递给后续的then()和map()函数

在下面的示例中,我使用的是蓝鸟库:

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

var getFiles = function (dir) {
      return fs.readdirAsync(dir);
  };

Promise.map(directories, function(directory) {
    return getFiles(directory)
  }).map(function (files) {
    // which directory's files are these?
    return files;
  })
下一步是迭代文件并读取它们的数据


我不介意答案是ES6、蓝鸟还是Q。我不知道蓝鸟,但这是ES6方法

var fs = require('fs');
var directories = ['/dir1', '/dir2'];
var result = {};
Promise.all(directories.map(function(dir) {
  result[dir] = {};
  return new Promise(function(resolve, reject) {
    fs.readdir(dir, function(er, files) {
      if (er) {
        return reject(er);
      }
      resolve(files);
    });
  }).then(function(files) {
    return Promise.all(files.map(function(file) {
      return new Promise(function(resolve, reject) {
        fs.readFile(dir + '/' + file, function(er, data) {
          if (er) {
            return reject(er);
          }
          result[dir][file] = data.toString('base64');
          resolve();
        });
      });
    }));
  });
})).then(function() {
  console.log(result);
}).catch(function(er) {
  console.log(er);
});

使用蓝鸟最简单的方法是:


不要使用这个工具!非常感谢您的回答@Tresdin,我理解它是如何工作的,并且欣赏ES6方法,但是我有点失望,因为它看起来像是我试图避免的回调地狱。@DenizOzger是的,我也是。实际上,我更喜欢
async
模块,因为它更快、更容易阅读哇,我很高兴我现在用的是蓝鸟。“蓝鸟”的效果更好。为什么要在数组上使用
..keys(目录)
?@Bergi是个打字错误,抱歉,现在编辑了。@DenizOzger你对递归路径解析和嵌套目录感兴趣吗?@BenjaminGruenbaum是的,只要我能将文件数据映射到文件名,将文件名映射到目录,一切正常。@DenizOzger您使用的是什么版本的node/io?Get
TypeError:无法读取第三行未定义的
的属性'then'。我们的fs定义相同吗?也就是说,
fs=promisefyall(require('fs'))
Yes,这应该是一个
fs.statAsync
当然:-)当然:-)我把这个数组传递给函数:
['/dir1','/dir2']
。在.reduce()回调的第一次执行中,obj是
{}
,路径是
'/dir1'
。在第二次执行中,obj是
未定义的
,路径是
'/dir2'
。这最终导致未定义的
无法设置属性“/dir2”
reduce函数不是这个吗?:我的意思是,如果在枚举过程中添加了一个文件/目录,它将在这里中断(如果它在stat中并且不存在,因为服务器会更改内容)。通过对代码的最新编辑,这似乎得到了解决
function getFiles(paths) { // an array of file/directory paths
    return Promise.props(paths.reduce(function (obj, path) {
        obj[path.split("/").pop()] = fs.statAsync(path).then(function (stat) {
            if (stat.isDirectory())
                return fs.readdirAsync(path).map(function (p) {
                    return path + "/" + p;
                }).then(getFiles);
            else if (stat.isFile())
                return fs.readFileAsync(path);
        }).error(function (e) {
            console.error("unable to read " + path + ", because: ", e.message);
            // return undefined; implied
        });
        return obj;
    }, {}));
}