1

I am using Node.js and the fs module. When a file is uploaded, I want to rename it to its original name and log the updated name (original name). My code for renaming an uploaded file works fine. But I am having trouble printing fileName.

let fileName = "";
form.on('file', function(field, file) {
    fs.rename(file.path, path.join(form.uploadDir, file.name), function(err) {
        if (err != null) {
            console.log(err);
        }
        fileName = path.join(form.uploadDir, file.name);
    });
});

let name = fileName;
console.log("NAME " + name);

What should I do differently?

EDIT: This is not a duplicate as the question really is specifically about fs.rename, not how to bypass asynchronous property

kevin_b
  • 113
  • 1
  • 11
  • Which line runs first? `fileName = ...` or `console.log("NAME " + fileName)`? – Kirk Larkin Oct 31 '17 at 21:38
  • Is anything logged to console or does nothing happen at all? – Niklas Higi Oct 31 '17 at 21:39
  • `console.log("NAME " + fileName)` prints only NAME – kevin_b Oct 31 '17 at 21:41
  • 2
    The `console.log` in the last line will execute before the callback to `fs.rename`, so the `fileName === ""` at the moment of logging. Move the console.log to the callback function. – pawel Oct 31 '17 at 21:41
  • fileName is empty @Kirk – kevin_b Oct 31 '17 at 21:42
  • @pawel I want to use this fileName as a variable in other parts of my code, so if I move it inside then it is out of scope – kevin_b Oct 31 '17 at 21:42
  • maybe I have to use a promise to make sure the callback is done before logging it – kevin_b Oct 31 '17 at 21:44
  • But is it a good practice to use promises in backend server code? – kevin_b Oct 31 '17 at 21:44
  • You can have the variable in whatever scope you want. What matters is that it is assigned the value asynchronously in the callback so it may or may not contain what you expect when accessed later in the program. – pawel Oct 31 '17 at 21:45
  • And being async, non-blocking and, by extension, utilising Promises or async/await is kind of the selling point of Node so yes, it is perfectly okay to embrace it in backend code. – pawel Oct 31 '17 at 21:48
  • ok solved it using promise – kevin_b Oct 31 '17 at 21:53

1 Answers1

1

With insights from @pawel, I used promises to solve this. I did not know whether it's good practice to use promises on server side Node.js.

let fileName = "";
let p = new Promise((resolve, reject) => {
    form.on('file', function (field, file) {
        fs.rename(file.path, path.join(form.uploadDir, file.name), function (err) {
            if (err != null) {
                console.log(err);
                reject(err);
            }
            fileName = path.join(form.uploadDir, file.name);
            resolve(fileName);
        });
    });
});

p.then((fileName) => {
    console.log("NAME " + fileName);
});
kevin_b
  • 113
  • 1
  • 11
  • You should also add `reject(err)` in `if(err != null)`, because now you have unhandled promise rejection. – pawel Oct 31 '17 at 22:02
  • @pawel yes you are right. Updated. – kevin_b Oct 31 '17 at 22:34
  • Inside `(field, file) { ... }` it would be easier to do `const fileName = path.join(form.uploadDir, file.name); util.promisify(fs.rename)(file.path, fileName).then(() => resolve(fileName), reject);` Although it would be more efficient to do `const rename = util.promisify(fs.rename)` in the outer scope and just call `rename(file.path, fileName).then(...)` inside the callback. – Patrick Roberts Nov 01 '17 at 18:39