use*_*195 3 javascript recursion node.js promise
我知道我在以下函数中提前返回,如何将递归promises链接到我的结果?
我的目标是获取目录中所有文件列表及其所有子目录.数组是单维的,我在这个例子中使用了concat.
function iterate(body) {
return new Promise(function(resolve, reject){
var list = [];
fs.readdir(body.path, function(error, list){
list.forEach(function(file){
file = path.resolve(body.path, file);
fs.stat(file, function(error, stat){
console.log(file, stat.isDirectory());
if(stat.isDirectory()) {
return iterate({path: file})
.then(function(result){
list.concat(result);
})
.catch(reject);
} else {
list.push(file);
}
})
});
resolve(list);
});
});
};
Run Code Online (Sandbox Code Playgroud)
jfr*_*d00 11
您的代码中存在许多错误.部分清单:
.concat()
返回一个新数组,因此list.concat(result)
它本身并没有做任何事情.
您正在resolve()
同步调用而不是等待所有异步操作完成.
您试图以递归方式从几个嵌套的异步回调中深入返回.你不能这样做.这不会让结果回到任何地方.
通过使用fs
模块的promisified版本,我发现这更容易使用.我使用Bluebird创建它,然后你可以这样做:
const path = require('path');
var Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
function iterate(dir) {
return fs.readdirAsync(dir).map(function(file) {
file = path.resolve(dir, file);
return fs.statAsync(file).then(function(stat) {
if (stat.isDirectory()) {
return iterate(file);
} else {
return file;
}
})
}).then(function(results) {
// flatten the array of arrays
return Array.prototype.concat.apply([], results);
});
}
Run Code Online (Sandbox Code Playgroud)
注意:我改为iterate()
只采取初始路径,因此它更通用.您body.path
最初可以通过它来适应.
这是使用通用ES6承诺的版本:
const path = require('path');
const fs = require('fs');
fs.readdirAsync = function(dir) {
return new Promise(function(resolve, reject) {
fs.readdir(dir, function(err, list) {
if (err) {
reject(err);
} else {
resolve(list);
}
});
});
}
fs.statAsync = function(file) {
return new Promise(function(resolve, reject) {
fs.stat(file, function(err, stat) {
if (err) {
reject(err);
} else {
resolve(stat);
}
});
});
}
function iterate2(dir) {
return fs.readdirAsync(dir).then(function(list) {
return Promise.all(list.map(function(file) {
file = path.resolve(dir, file);
return fs.statAsync(file).then(function(stat) {
if (stat.isDirectory()) {
return iterate2(file);
} else {
return file;
}
});
}));
}).then(function(results) {
// flatten the array of arrays
return Array.prototype.concat.apply([], results);
});
}
iterate2(".").then(function(results) {
console.log(results);
});
Run Code Online (Sandbox Code Playgroud)
这是一个添加可自定义过滤功能的版本:
function iterate2(dir, filterFn) {
// default filter function accepts all files
filterFn = filterFn || function() {return true;}
return fs.readdirAsync(dir).then(function(list) {
return Promise.all(list.map(function(file) {
file = path.resolve(dir, file);
return fs.statAsync(file).then(function(stat) {
if (stat.isDirectory()) {
return iterate2(file, filterFn);
} else {
return filterFn(file)? file : "";
}
});
})).then(function(results) {
return results.filter(function(f) {
return !!f;
});
});
}).then(function(results) {
// flatten the array of arrays
return Array.prototype.concat.apply([], results);
});
}
// example usage
iterate2(".", function(f) {
// filter out
return !(/(^|\/)\.[^\/\.]/g).test(f);
}).then(function(results) {
console.log(results);
});
Run Code Online (Sandbox Code Playgroud)