bluebird - 函数返回promise对象而不是实际数据

时间:2016-11-19 14:11:10

标签: javascript node.js bluebird

关注this snippet我正在尝试编写一个循环通过目录的函数,查找目录,并从这些目录中读取xml文件名(我知道文件夹结构将始终保持不变)。到目前为止,我的函数正在按预期工作,但是当我尝试从函数返回时,我只获取Promise对象。

我的代码:

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

当我在console.log(files)内的最后一个.then函数内getFileNames时,我在控制台中获得了实际的文件名数组。但是当我运行上面的代码时,我得到了这个输出:

[ 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 } ]

为什么会发生这种情况以及如何解决?

4 个答案:

答案 0 :(得分:2)

在行

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

您正在为一系列承诺创建承诺,而这正是您在最终日志中获得的承诺。你需要返回一个值数组的承诺,而不是返回一个promises数组 - Promise.all就是这样:

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

但是,在Bluebird中,使用Promise.map(directories, function(…) { … })甚至the map method会更加惯用(类似于您已经对每个目录中的文件使用.filter所做的那样):

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

答案 1 :(得分:0)

试试这个

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

答案 2 :(得分:0)

这段代码:

.then(function(directories) {
   return directories.map(function(directory) {
     return fs.readdirAsync(path.join(rootPath, directory))
     ...

会向当时的回调返回一个promises数组。 Promise数组在此处计为立即值,不会与数组的Promise相关联。要将promises数组转换为数组的promise,可以使用Promise.all,但由于您使用的是bluebird,因此您有更好的选择:

您所要做的就是使用Promise.map

.then(function(directories) {
   return Promise.map(directories, function(directory) {
     return fs.readdirAsync(path.join(rootPath, directory))
     ...

答案 3 :(得分:0)

想出来,第二个函数有一个。然后太多了:

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)
      .then(function(content) {
        return content.filter(function(file) {
          return fs.statSync(path.join(rootPath, file)).isDirectory();
        });
      })
      // For every directory
      .map(function(directory) {
        // Read files in the directory
        return fs.readdirAsync(path.join(rootPath, directory))
            .filter(function(file) {
              return path.extname(file) == '.XML';
            });
      });
}

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