Q Promises — функция Node.js для каждого элемента массива
-
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;
});
});
}