2013-08-27 2 views
1

Я изучаю nodejs. Мне сложно понять, как работают асинхронные функции. Мой вопрос связан с приведенным ниже кодом. Я пытаюсь сделать следующее в следующем точно таком же порядке:Понимание асинхронных функций в node.js

  1. Открыть файл a.txt.
  2. Прочтите.
  3. Распечатать содержание.
  4. Закройте его и запишите, что файл был закрыт.
  5. Открыть его снова.
  6. Перезаписать его новым контентом.

Проблема в том, что в соответствии с выходом, который я получаю, кажется, что я не контролирую последовательность этих событий. Это выход я получаю в консоли:

просто читать 21 байт/это мои тестовые файлы/только что написал 30 байт/файл близко и готов к записи

Итак, как вы можете видеть, для некоторых причина, по которой программа записывает в файл до того, как он зарегистрирует, что файл был закрыт. Я пытался закрыть его, зарегистрировать, что он был закрыт, а затем записать в файл.

Таким образом, я думаю, что у меня есть проблема с управлением потоком событий. Можете ли вы указать, что я делаю неправильно?

этого код:

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.'); 
    } 
    }); 
}); 

ответ

1

Все эти операции являются асинхронными, так что вы не можете вызвать fs.open('a.txt', 'r+') на верхнем уровне вашего кода - это будет вызываться сразу после fs.open('a.txt', 'r'), что приводит к неожиданным результатам вы получаете.

Посмотрите на writeToAFile(), который вызывается при обратном вызове для первого fs.close(). Это ключ к тому, что файл сначала считывается, закрывается, а затем записывается и закрывается.

Вот исправление:

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 
    }); 
    }); 
} 
1

Вы должны ждать, пока шаг 4 не будет сделано перед вызовом fs.open снова.

Сейчас ваш код вида выглядит

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") 
    }) 
}); 

Для сохранения заказа Вам необходимы гнездиться функции:

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") 
      }) 
     }); 
    }) 
}); 

Конечно, это выглядит очень некрасиво и neting 4+ уровней глубины трудно читать. Вы можете сделать это выглядеть немного лучше, создавая дополнительные именованные функции

console.log("done with first file"); 
    doThingsWithSecondFile(); 

Или вы можете посмотреть в библиотеках, как async.js или обещания. (Эти библиотеки особенно полезны, если вы хотите улучшить обработку ошибок по умолчанию)

Смежные вопросы