在Array.forEach块中的所有promise都已解决后返回

时间:2016-03-07 22:49:08

标签: javascript node.js promise es6-promise

我在一个简单的示例中尝试了nodejs中的es6-promisify模块,类似于npm page of es6-promisify上的示例。 但我想使用forEach循环来检查条目的统计信息,如果它们是目录,则将它们推送到一个单独的数组:

var fs=require('fs');
var promisify=require('es6-promisify');
var path='../test_folder/';
function listSubfolderNamesSync(fpath){
    var arrayOfFolders=[];
    var array=fs.readdirSync(fpath);
    array.forEach(function(element,index,array){
        var stat=promisify(fs.stat);
        stat(path+element).then(function(stats){
            if (stats.isDirectory()){
                arrayOfFolders.push(element);
                console.log('pushed');
            }
        })
    });
    return arrayOfFolders;
}

console.log(listSubfolderNamesSync(path));

有2个子文件夹,输出为:

[]
pushed
pushed

我知道为什么我的代码不能像我想的那样工作,但我无法弄清楚如何优雅地解决这个问题。我已经看到了Promise.all()的代码示例和Array.map()的使用,以获得一组promises并等待所有这些都在链中前进之前解析。我看到的问题是,我无法在每次检查统计信息时明确创建承诺,并将这些承诺放在数组中以使用Promise.all(array)。我觉得解决方案需要相当多的解决方案,并且会大大降低代码的可读性。 也许最好只在forEach循环中使用它,这是我在尝试宣传之前的工作代码:

if(fs.statSync(path+element).isDirectory()){
        arrayOfFolders.push(element);
}

可能是因为我缺乏编程经验,但似乎混合承诺,回调和同步代码并不像书中写的那么简单?

1 个答案:

答案 0 :(得分:1)

stat()返回一个承诺时,您的listSubfolderNamesSync()函数也必须返回listSubfolderNamesAsync()。除非有stat()的同步替代方案,否则这是不可避免的。

listSubfolderNamesAsync()内,您需要将fs.readdirSync()返回的数组映射到promises数组,然后使用Promise.all()将这些promises(以及它们提供的数据)聚合到一个的承诺。

var fs = require('fs');
var promisify = require('es6-promisify');
var stat = promisify(fs.stat);

var path = '../test_folder/';

function listSubfolderNamesAsync(fpath) {
    var promises = fs.readdirSync(fpath).map(function(element) {
        return stat(path + element).then(function(stats) {
            return stats.isDirectory() ? element : null;
        });
    });
    return Promise.all(promises).then(function(results) {
        return results.filter(function(res) {
            return res !== null;
        });
    });
}

现在使用.then()处理结果:

listSubfolderNamesAsync(path).then(function(folders) {
    console.log(folders);
});

在使用更通用的函数返回单独的文件夹文件列表时,没有明显的性能损失。你可以这样写:

function listSubElementsAsync(fpath) {
    var promises = fs.readdirSync(fpath).map(function(element) {
        return stat(path + element).then(function(stats) {
            var type = stats.isDirectory() ? 'folder' : 'file';
            return {type:type, element:element};
        });
    });
    return Promise.all(promises).then(function(results) {
        var files = results.filter(obj => obj.type === 'file').map(obj => obj.element);
        var folders = results.filter(obj =>  obj.type === 'folder').map(obj => obj.element);
        return {files:files, folders:folders};
    });
}
listSubElementsAsync(path).then(function(list) {
    console.log(list.files);
    console.log(list.folders);
});