You can't use an async callback with .filter(). .filter() expects a synchronous result and there is no way to get a synchronous result out of an asynchronous operation. So, if you're going to use the asynchronous fs.stat(), then you will have to make the whole operation async.
Here's one way to do that. Note even randomFile() needs to communicate back it's result asynchronously. Here we use a callback for that.
const path = require('path');
const fs = require('fs');
exports.randomFile = function(dir, callback) {
fs.readdir(dir, (err, files) => {
if (err) return callback(err);
function checkRandom() {
if (!files.length) {
// callback with an empty string to indicate there are no files
return callback(null, "");
}
const randomIndex = Math.floor(Math.random() * files.length);
const file = files[randomIndex];
fs.stat(path.join(dir, file), (err, stats) => {
if (err) return callback(err);
if (stats.isFile()) {
return callback(null, file);
}
// remove this file from the array
files.splice(randomIndex, 1);
// try another random one
checkRandom();
});
}
checkRandom();
});
}
And, here's how you would use that asynchronous interface form another module.
// usage from another module:
var rf = require('./randomFile');
fs.randomFile('/temp/myapp', function(err, filename) {
if (err) {
console.log(err);
} else if (!filename) {
console.log("no files in /temp/myapp");
} else {
console.log("random filename is " + filename);
}
});