0

I am deleting somefiles using fs.unlink and then I want to run some code. Due to the async nature of JS what is happening is that my code after unlinking is called before the callback of unlink. How can i Syncronise this? Is promises the only way ?

fs.unlink("FileName",function(err){
   console.log("RUN");
})

for(let i = 0; i<10;i++) {
   console.log(i);
}

RESULT :

1
2
3
4
5
6
7
8
9
RUN

The problem with using promises is that : If i have many files to delete, then i will have maintain a count of the promises and then check how many have been resolved. This i want to avoid

Bhumi Singhal
  • 8,063
  • 10
  • 50
  • 76
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Brahma Dev Sep 25 '17 at 11:17
  • Just move the loop inside your callback? – Bergi Sep 25 '17 at 11:24
  • The answer to your promise problem is `Promise.all`. That's actually substantially simpler than keeping count manually with callbacks. – Bergi Sep 25 '17 at 11:25
  • @Bergi : this is a toned down version of the code. that loop is a full blown fucntion in itself and i will like to keep it outside the callback as i have to delete 4 files. – Bhumi Singhal Sep 25 '17 at 11:28
  • @BhumiSinghal Well if you don't post your actual code we can only give toned down solutions. (Still, you should just use promises like in Adams answer) – Bergi Sep 25 '17 at 12:43
  • @Bergi : yes true. that is why i added the issue that i think is with Promises and .all() seems to be the solution to that. Thank you – Bhumi Singhal Sep 26 '17 at 04:28

4 Answers4

3

In this situation, you can use fs.unlinkSync, the synchronous version of fs.unlink:

try {
  fs.unlinkSync("FileName");
  console.log('Removing file successful!');
} catch(e) {
  // TODO: handle errors here
};

console.log("RUN");

for(let i = 0; i<10;i++) {
   console.log(i);
}

As @Keith rightfully mentions in the comments: synchronous operations like this should be use sparingly. If you have large numbers of files to delete, it may be better to use the asynchronous fs.unlink() because you can "start" more of those concurrently (tradeoff: start too many and the performance may suffer because of I/O saturation).

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • what can i do if i want to console.log when the try statement does not give an error. Like i want to print a successfull file removal – Bhumi Singhal Sep 25 '17 at 11:31
  • @BhumiSinghal see edit, it's basically a `console.log()` statement _inside_ the `try` block. – robertklep Sep 25 '17 at 11:32
  • This solution really needs a health warning on scale-ability.. :) – Keith Sep 25 '17 at 11:41
  • @Keith "perhaps". I don't know the specific situation and was proposing a solution for the code that was posted. I do wonder how unscalable `fs.unlinkSync` really is though. – robertklep Sep 25 '17 at 11:44
  • Yeah!, not saying your answer is wrong, but I just thinks it's always worth mentioning the performance issues with `sync` code. `I do wonder how unscalable fs.unlinkSync`, Well it depends, in this case it might be minimal,. But if say you had 100 files you wanted to delete, using async code would allow you to push 100 files to delete to the OS, rather than waiting for each one to be deleted first, and all at the same time say been able to accept say a web requests from a user. etc.. ps. Not me who down-voted you. – Keith Sep 25 '17 at 11:49
  • Nice update, up-voted. Nice point about too many at once due to IO saturation. Using something like bluebirds, map concurrency or similar is ideal for that. – Keith Sep 25 '17 at 12:00
  • @keith : i get the concern. But currenty my requirement is that the files should be clean and then i should be writting to them. SO the current code works for me . Thank you – Bhumi Singhal Sep 26 '17 at 04:31
  • @robertklep : A question : what is making the code run syncronously ? The function unlinkSync makes the removal of the files happen syncronously with respect to the code and that why the execution thread waits for that to end and then move to for loop? – Bhumi Singhal Sep 26 '17 at 04:38
  • @BhumiSinghal it runs synchronously because it was implemented that way :D the event loop is blocked until the call has finished (as with all other `*Sync()` functions in `fs`) – robertklep Sep 26 '17 at 05:40
2

Using Promises is a good solution, you don't have to track the promises yourself, bluebird will do it for you:

const Promise = require('bluebird');

function unlinkFile(fileName) {
    return new Promise((resolve, reject) => {
        fs.unlink(fileName, function (err) {
            if (err) {
                return reject(err);
            }
            resolve();
        });
    });
}

Promise.all([unlinkFile('01.txt'), unlinkFile('02.txt'), unlinkFile('03.txt')])
    .then(() => {
        console.log('ALL FILES UNLINKED');
    });

// OR YOU CAN USE promise.map

const filesToUnlink = ['01.txt', '02.txt', '3.txt'];
Promise.map(filesToUnlink, unlinkFile)
    .then(() => {
        console.log('ALL FILES UNLINKED');
    });
Adam
  • 4,985
  • 2
  • 29
  • 61
  • 1
    If your using Bluebird, it comes with promisify. You could just then do `var unlinkFile = Promise.promisify(fs.unlink)` – Keith Sep 25 '17 at 11:42
0

Promise is not the only way. You can wrap your for loop in a function, and call that function from the unlink callback.

fs.unlink("FileName",function(err){
    console.log("RUN");
    loop();
})

function loop() {
    for(let i = 0; i<10;i++) {
       console.log(i);
    }
}

On the other hand, with a Promise you would do this way :

new Promise((resolve, reject) => {
    fs.unlink("FileName",function(err){
        console.log("RUN");
        return resolve(); 
    });
})
.then(() => {
    for(let i = 0; i<10;i++) {
        console.log(i);
    }
});

But, as @robertklep says, if your code does not need async, just call the synchronous function.

Francois
  • 3,050
  • 13
  • 21
0

You should use Promise to get proper result.

let fs = require('fs');
new Promise((resolve,reject) => {
    fs.unlink("demo1.txt", function (err) {
        console.log("RUN");
        if(err)
            reject(err);
        resolve();
    })
})
.then(() => {
        for (let i = 0; i < 10; i++) {
            console.log(i);
        }
    },(error)=>{
        console.log(error);
    })
Rahul Patil
  • 493
  • 5
  • 14