Reputation: 18821
Question: Why won't a var things
return a value from outside the walk()
function? And how do I fix it?
Hypothosis: this is async and the console.log is happening too early. Which would lead me to how can I make this a Promise
(i'm using node 4.1.1)
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
file = dir + '/' + file;
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
next();
});
} else {
results.push(file);
next();
}
});
})();
});
};
function traverseDirectories() {
var things = walk('src/', function(err, results){
if(err) throw err;
console.log(results) // ['dir/thing.png', 'dir/thing2.png']
return results;
});
console.log(things) // undefined
};
traverseDirectories();
Upvotes: 2
Views: 59
Reputation: 11735
Q. Why won't a var things return a value from outside the walk() function?
R. Because walk
doesn't return anything (take a look and you''ll see that it's a void
function).
Even if you make it a Promise, you won't be able to use it like:
var things = walk(...);
console.log(things);
Because Promises are thenable, and are still async, so it will be:
walk(...).then(function(things) {
// do something with things here
});
To do what you want, you would need something that doesn't exist in current Javascript yet.
There is an ES7 proposal of native async/await
that will be a callback heaven, but atm, you can use:
But, if you're already using the newest version of NodeJS (4.0.0 as the time of writing) - and if you're not, you really should - the best way of achieving what you want is to use generators.
Combined with a small library named co, it will help you to achieve almost what the ES7 async/await
proposes, and it will mostly use native code, so both readability and performance are really good:
var co = require('co');
var traverseDirectories = co(function *traverseDirectories() {
var things = yield walk('src/');
console.log(things) // there we go!
});
function walk(dir, results) {
return new Promise(function(resolve, reject) {
fs.readdir(dir, function(err, list) {
if (err)
reject(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) resolve(results);
file = dir + '/' + file;
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file).then(function(res) {
results = results.concat(res);
next();
});
} else {
results.push(file);
next();
}
});
})();
});
});
}
You can read more about this subject in this awesome Thomas Hunter's blog post.
Upvotes: 1