Reputation: 51
I am learning nodejs. I am having some hard time understanding how asynchronous functions works. My question is related to the code below. I am trying to do the following things in the following exact same order:
The problem is that as per the output I am getting, it seems that I am not controlling the sequence of these event. This is the output I am getting in the console:
just read 21 bytes / this is my test files / just wrote 30 bytes /file close and ready for write
So, as you can see, for some reason the program is writing in the file before it log that the file was closed. I was trying to close it, log that it was closed and then to write in the file.
So I think I have a problem controlling the flow of events. Can you point out what am I doing wrong?
This the the code:
var fs = require('fs');
//What I am trying to do here is: open a file a.txt, read it, print its content and then //close the file and log that it has been closed.
//Then, open it again and overwrite it.
fs.open('a.txt', 'r', function(err, fd){
if(err){throw err;}
var readBuffer = new Buffer(1024);
var bufferOffset = 0;
var filePosition = 0;
var readBufferLength = readBuffer.length;
fs.read(fd, readBuffer, bufferOffset, readBufferLength, filePosition, function(err, readBytes){
if(err){throw err;}
console.log('just read ' + readBytes + ' bytes');
console.log(readBuffer.slice(0,readBytes).toString());
fs.close(fd,function(){
console.log('file close and ready for write');
});
});
});
fs.open('a.txt', 'r+', function(err,fd){
if(err){throw err;}
var writeBuffer = new Buffer('saul lugo overwrote this file!');
var bufferOffset = 0;
var writeBufferLength = writeBuffer.length;
var filePosition = null;
fs.write(fd, writeBuffer, bufferOffset, writeBufferLength, filePosition, function(err, writeBytes){
if(err){throw err;}
if(writeBytes>0){
console.log('just wrote ' + writeBytes + ' bytes.');
}
});
});
Upvotes: 1
Views: 583
Reputation: 35950
All of those operations are asynchronous, so you cannot invoke fs.open('a.txt', 'r+')
at the top-level of your code - it will be invoked immediately after fs.open('a.txt', 'r')
which leads to the unexpected results you're getting.
Take a look at writeToAFile()
which is getting invoked in a callback for first fs.close()
. This is the key to making sure file is first being read, closed and then wrote to and closed.
Here is a fix:
var fs = require('fs');
fs.open('a.txt', 'r', function(err, fd){
// do stuff ...
fs.read(/* params */, function(err, readBytes){
// do stuff ...
fs.close(fd,function(){
// now open file again for writing
writeToAFile();
});
});
});
// This will be called inside the callback handler for closing the file.
// This way file will be opened for reading, read, close and THEN opened for writing.
function writeToAFile () {
fs.open('a.txt', 'r+', function(err,fd){
// do stuff ...
fs.write(/* params */, function(err, writeBytes){
// do stuff ...
// close file
});
});
}
Upvotes: 1
Reputation: 69924
You need to wait until step 4 is done before calling fs.open again.
Right now your code kind of looks like
fs.open("a.txt", function(){
foo(function(){
console.log("done with first file")
})
});
fs.open("a.txt", function(){
foo(function(){
console.log("done with second file")
})
});
To preserve the order you need to nest the functions:
fs.open("a.txt", function(){
foo(function(){
console.log("done with first file")
fs.open("a.txt", function(){
foo(function(){
console.log("done with second file")
})
});
})
});
Of course, this now looks very ugly and neting 4+ levels deeps is hard to read. You can make it look a little better by creating extra named functions
console.log("done with first file");
doThingsWithSecondFile();
Or you could look into libraries like async.js or promises. (These libraries are specially useful if you want better error handling by default)
Upvotes: 1