javascript - 在 Array.forEach block 中的所有 Promise 都已解决后返回

标签 javascript node.js promise es6-promise

我正在尝试使用 Node.js 中的 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() 的用法拥有一系列 promise 并等待所有 promise 都得到解决,然后再在链条中前进。我看到的问题是,我不能/不想每次检查统计数据时显式创建一个 promise 并将这些 promise 放入数组中以使用 Promise.all(array) 。我感觉该解决方案需要相当多的解决方法,并且会大大降低代码的可读性。 也许最好在 forEach 循环中使用它,这是我在尝试 promisify 之前的工作代码:

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

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

最佳答案

由于 stat() 返回一个 promise ,您的 listSubfolderNamesSync() 函数也必须返回一个 promise ,使其成为 listSubfolderNamesAsync()。除非可以使用 stat() 的同步替代方法,否则这是不可避免的。

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

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

关于javascript - 在 Array.forEach block 中的所有 Promise 都已解决后返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35855709/

相关文章:

node.js - 在异步/等待中包装 promise

javascript - 将已解决的 promise 值传递到最终的 "then"链的最佳方法是什么

javascript - 如何在javascript中获取所有数字

javascript - HTML 动态/响应元素定位

javascript - GraphQL 解析器 - 在 promise 解决后返回我的函数

node.js - docker 卷 : data lost when container is removed or stopped and then restarted

javascript - 将嵌套 Promise 中的 catch block 放入内部以触发外部 Promise 的 catch block ,是否有其他更清洁的方法?

javascript - Moment.js 在解析验证期间忽略星期几

javascript - 缩略图 CSS 强制 div 到下一行

javascript - 如何制作汇总模块,重新导出ESM模块的所有子模块导出?