为什么承诺首先解决?

时间:2017-05-09 14:25:23

标签: javascript promise

根据stackoverflow上的代码片段,我想读取目录中的所有文件,然后继续。 我已经添加了一个承诺,但这在某种程度上是行不通的。

我的目录包含2个文件,控制台日志输出为:
承诺解决了 文件名内部 文件名内部 里面的readFiles
在readFiles里面

function readFiles(dirname, onFileContent, onError) {
    return new Promise((resolve, reject) => {
        fs.readdir(dirname, function(err, filenames) {
            filenames.forEach(function(filename) {

                console.log('inside filenames');

                fs.readFile(dirname + filename, 'utf-8', function(err, content) {
                    onFileContent(filename, content);
                });
            });
        });
    });
}

var data = [];
readFiles('datadir/', function(filename, content) {
    console.log('inside readFiles');
    data.push(filename);
}).then(
    console.log('promise resolved');
    //proceed handling the data-array
);

1 个答案:

答案 0 :(得分:1)

承诺不会首先解决"。在读取第一个文件之前执行对console.log的调用。

您永远不会在您的承诺上致电resolve,因此永远不会调用then。但是,您已将console.log结果传递给thenconsole.log的结果无效。

您可以通过更正问题来测试:

readFiles('datadir/', function(filename, content) {
    console.log('inside readFiles');
    data.push(filename);
}).then(function(){ // NOTE: addition of function(){..}
    console.log('promise resolved');
    //proceed handling the data-array
});

您会注意到该消息永远不会写入控制台。

所以这是错的 - 如何解决它。需要一些思考来围绕节点中完全基于异步/承诺的代码。

我假设您要等待所有文件在解决您的承诺之前阅读内容。这有点棘手,因为你有2个异步调用(读取文件列表,然后分别读取它们的内容)。将文件的读取包装成自己的承诺可能更容易。像这样:

function readFile(filePath){
    return new Promise((resolve,reject) => {
       fs.readFile(filePath, "utf-8", function(err,content) => {
           if(err) reject(err)
           else resolve({path:filePath, content:content})
        });
    });
}

readdir执行相同操作,以使其也可链接:

function readDirectory(dir){
    return new Promise((resolve,reject) => {
       fs.readdir(dirname, function(err, filenames) {
          if(err) reject(err);
          else{
             resolve(filenames.map(fn => dir + fn));
          }
      });
    });
}

执行此操作的原因是您可以在Promise.all上链接以等待所有文件内容。

function readFileContents(dirname) {
    return readDirectory(dirname)
            .then(files => 
                 Promise.all(files.map(file => readFile(file))
             );
}

用法:

readFileContents('datadir/').then(files => {
    files.forEach(file => {
        console.log(file.path, file.content.length);
    });
});