了解node.js中的异步函数

Understanding asynchronous functions in node.js

本文关键字:异步 函数 node js 了解      更新时间:2023-09-26

我正在学习nodejs。我很难理解异步函数是如何工作的。我的问题与下面的代码有关。我正试图按照以下完全相同的顺序做以下事情:

  1. 打开文件.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.');
    }
    });
});

在再次调用fs.open之前,您需要等待步骤4完成。

现在你的代码看起来有点像

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或promise之类的库。(如果默认情况下想要更好的错误处理,这些库特别有用)

所有这些操作都是异步的,因此您不能在代码的顶层调用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
    });
  });
}