Reputation: 555
I'm trying to list files sending a POST
request, but I can't figure out what's wrong with what I am doing. Here's my function:
app.post('/api/list', function(req,res){
listFiles();
res.send(files);
});
And here is my listFiles
function and test variable :
var files = "";
var listFiles = function(){
fs.readdir(testFolder, (err, files) => {
files.forEach(file => {
files += file;
});
console.log(files);
})
};
I can see the paths with a console.log
output. But, when I use res.send(files);
in the POST
, the files aren't shown - it's empty. Here's what I've written in jQuery to show the files:
$('li').on('click', function(){
var item = $(this).text().replace(/ /g, "-");
$.ajax({
type: 'POST',
url: '/api/list',
success: function(data){
//do something with the data via front-end framework
alert('response : ' + data);
//location.reload();
}
});
});
My connection is okay if I send res.send("test");
. I can make that alert message as "response : test"
. But when I try to send a variable it's empty.
Upvotes: 2
Views: 984
Reputation: 1816
Welcome to async programming! :)
fs.readdir
works asynchronously, so when you call listFiles()
, that returns immediately and goes on to the next line - res.send(files)
. At that moment files
really still is an empty string, so that's what you're seeing.
The callback of fs.readdir
is actually executed after res.send(files)
finishes, so you would either need to execute res.send()
in the same fs.readdir
callback, or control the flow with Promises.
Here are a few examples:
Pass res
to listFiles, execute res.send()
after you have the output you need
var listFiles = function (res) {
fs.readdir(..., (err, files) => {
var filesString = "";
files.forEach(...)
res.send(filesString)
})
};
app.post('/api/list', function(req,res){
listFiles(res);
});
Pass a callback to listFiles, similar to the first one but following the same pattern fs.readdir
uses
var listFiles = function (callback) {
fs.readdir(..., (err, files) => {
var filesString = "";
files.forEach(...)
callback(filesString)
})
};
app.post('/api/list', function(req,res){
listFiles((filesString) => res.send(filesString));
});
Wrap fs.readdir
in a Promise (you can also use util.promisify
for this, check out the Node docs)
var listFiles = new Promise((resolve, reject) => {
fs.readdir(..., (err, files) => {
var filesString = "";
files.forEach(...)
return resolve(filesString)
})
})
app.post('/api/list', function(req,res){
listFiles().then((filesString) => res.send(filesString))
// or, even better as Express can reply with a Promise directly
// res.send(listFiles())
});
There's a nice series about NodeJS, async programming and the event loop, I recommend you to read up on it so you get the hang of the bigger picture: https://jsblog.insiderattack.net/event-loop-and-the-big-picture-nodejs-event-loop-part-1-1cb67a182810. Also, check out the stuff related to async/await, it makes Promises that much nicer to work with in most cases.
Upvotes: 2