简体   繁体   English

了解Node.js中的异步函数

[英]Understanding asynchronous functions in node.js

I am learning nodejs. 我正在学习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: 我试图按照以下完全相同的顺序执行以下操作:

  1. Open the file a.txt. 打开文件a.txt。
  2. Read it. 阅读。
  3. Print its content. 打印其内容。
  4. Close it and log that the file has been closed. 关闭它并记录该文件已关闭。
  5. Open it again. 再次打开它。
  6. Overwrite it with new content. 用新内容覆盖它。

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 刚读了21个字节/这是我的测试文件/刚写了30个字节/关闭并准备写文件

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

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. 所有这些操作都是异步的,因此您不能在代码的顶层调用fs.open('a.txt', 'r+') -它会在fs.open('a.txt', 'r')会导致您得到意想不到的结果。

Take a look at writeToAFile() which is getting invoked in a callback for first fs.close() . 看一下writeToAFile() ,它在第一个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
    });
  });
}

You need to wait until step 4 is done before calling fs.open again. 您需要等到第4步完成后,才能再次调用fs.open。

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. 当然,这看起来非常丑陋,很难读取4级​​以上的深度。 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. 或者,您可以研究async.js或promises之类的库。 (These libraries are specially useful if you want better error handling by default) (如果您希望默认情况下更好地处理错误,这些库特别有用)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM