2013-08-27 115 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或承諾圖書館更好一點。 (如果您希望默認更好的錯誤處理,這些庫特別有用)