Q Promises — функция Node.js для каждого элемента массива

StackOverflow https://stackoverflow.com//questions/22027792

  •  21-12-2019
  •  | 
  •  

Вопрос

Функция dirList() должен возвращать массив папок внутри определенного каталога.Я не могу понять, как вернуть dirList переменная только после функции isDir() выполняется для каждого файла.

Я думаю, что мне следует использовать Q.all(), но я не знаю, куда это положить :-(

var fs = require('fs'),
    Q = require('q'),
    readdir = Q.denodeify(fs.readdir);

function isDir(path) {
    return Q.nfcall(fs.stat, __dirname + path)
        .then(function (stats) {
            if (stats.isDirectory()) {
                return true;
            } else {
                return false;
            }
        });
}

function dirList(path) {
    return readdir(__dirname + path).then(function (files) {
        var dirList = files.filter(function (file) {
                return isDir(path + file).then(function (isDir) {
                    return isDir;
                });
            });
        return dirList;
    });
}

dirList('/').done(
    function (data) {
        console.log(data);
    },
    function (err) {
        console.log(err);
    }
);
Это было полезно?

Решение

Проблема, с которой вы столкнулись, заключается в том, что Array.prototype.filter не знает о промисах, поэтому просто видит истинное значение (на самом деле объект промиса) и добавляет файл в выходной список.Ниже приведен один из способов решения проблемы (может быть более «чистый» способ с чем-то вроде AsyncJS):

'use strict';

var fs = require('fs'),
    Q = require('q'),
    readdir = Q.denodeify(fs.readdir);

function isDir(path) {
    return Q.nfcall(fs.stat, __dirname + path)
        .then(function (stats) {
            return stats.isDirectory();
        });
}

function dirList(path) {
    return readdir(__dirname + path).then(function (files) {
        // here we map the list of files to an array or promises for determining
        // if they are directories
        var dirPromises = files.map(function (file) {
            return isDir(path + file);
        });
        // here is the Q.all you need
        return Q.all(dirPromises)
            // here we translate the array or directory true/false values back to file names
            .then(function(isDir) {
                return files.filter(function(file, index) { return isDir[index]; });
            });
    });
}

dirList('/').done(
    function (data) {
        console.log(data);
    },
    function (err) {
        console.log(err);
    });

Другие советы

Массив filter Метод не работает с результатом асинхронного обещания, он ожидает, что логическое значение будет возвращено синхронно.

Я бы предложил использовать функцию, которая проверяет, является ли данный путь каталогом, и возвращает обещание для файла, если это так, и обещание ни о чем в противном случае.Затем вы можете подождать с Q.all() для результатов этого для каждого пути, а затем объединить «положительные» результаты вместе, опуская «отрицательные»:

function isDir(path) {
    return Q.nfcall(fs.stat, __dirname + path).invoke("isDirectory");
}

function dirList(path) {
    return readdir(__dirname + path).then(function (files) {
        var maybeDirPromiseList = files.map(function (file) {
            return isDir(path + file).then(function (isDir) {
                return isDir ? [file] : []; // Maybe represented as list
            });
        });
        var maybeDirsPromise = Q.all(maybeDirPromiseList);
        return maybeDirsPromise.then(function(maybeDirList) {
             return [].concat.apply([], maybeDirList);
             // is equivalent to:
             var dirList = [];
             for (var i=0; i<maybeDirList.length; i++)
                 if (maybeDirList[i] && maybeDirList[i].length > 0)
                     dirList.push(maybeDirList[i][0]);
             return dirList;
        });
    });
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top