为什么我在Node.js中的同一段代码会得到不同的输出?

rdlzhqv9  于 2023-05-22  发布在  Node.js
关注(0)|答案(1)|浏览(125)

我在Windows机器上运行的Node.js中的相同代码行得到了不同的输出。

我刚刚开始使用Node.JS,并在附近玩了一会儿。我多次运行以下代码,令人惊讶的是得到了两个不同的输出(在终端上,以及文本文件)。我确实对JavaScript的异步有一些了解,但我没有想到同一行代码会有两个不同的输出。

const fs=require('fs');
const path=require('path');
console.log("Blah blah");
fs.writeFile(path.join(__dirname,'temp.txt'),'Hello!',(err)=>
{
    if(err)
        console.log(err);
    console.log('Write complete.');
    fs.appendFile(path.join(__dirname,'temp.txt'),'Bye-bye!',(err)=>
    {
        if(err)
            console.log(err);
        console.log('Inner append');
    });
});
fs.appendFile(path.join(__dirname,'temp.txt'),'Hi, again!',(err)=>
{
    if(err)
        console.log(err);
    console.log('Outer append');
});

我得到以下两个输出,沿着文本文件的内容:
Output of the code
第一个输出:

Blah blah
Write complete.
Outer append
Inner append

第二输出:

Blah blah
Outer append
Write complete.
Inner append

对应于第一输出的文本文件的内容:

Hello!Hi, again!Bye-bye!

对应于第二输出的文本文件的内容:

Hello!ain!Bye-bye!

我期待第二个输出,但文本文件的相应内容实际上没有意义。请指出我是否有任何概念上的误解,以及同一代码有两种不同输出的原因。我的Node版本是v18.16.0。
请注意,我在相同的环境下得到不同的输出,不像在不同的环境下有相同问题的类似问题。
先谢谢你了!

csbfibhn

csbfibhn1#

为什么同一段代码会得到不同的输出,是因为Node.js是异步的,非阻塞的。这意味着它不会等待一个操作完成后再继续下一个操作,而是并行执行它们,并使用回调来处理结果。
在代码中,您使用fs模块执行文件操作,例如向文件写入数据和追加数据。这些操作是异步的,这意味着它们需要一些时间才能完成,并返回一个回调函数,当它们完成时将执行该函数。回调函数接受一个err参数,该参数指示操作过程中是否出错,还可以接受包含操作结果的其他可选参数。
代码的执行顺序如下:
1:需要fs和path模块,并将它们分配给变量。
2:你把"Blah blah"记录到控制台。
3:调用fs. writeFile来写"Hello!"添加到名为temp.txt的文件中。这是一个异步操作,因此Node.js不会等待它完成,而是传递一个回调函数,该函数将在操作完成后执行。回调函数将把任何错误或"Write complete."记录到控制台,然后调用fs.appendFile附加"Bye-bye!”到同一个文件。这也是一个带有回调函数的异步操作,回调函数将把任何错误或“内部追加”记录到控制台。
4:调用fs. appendFile来追加"Hi,again!”到同一个文件。这是另一个带有回调函数的异步操作,它将把任何错误或“外部追加”记录到控制台。
5:代码结束。
现在,根据每个异步操作完成的速度,回调函数的执行顺序可能会有所不同。例如,可能第4步中的fs.appendFile在第3步中的fs.writeFile之前完成,因此您将在控制台中的"Write complete."之前看到"Outer append"。也有可能第3步中的fs. writeFile在第4步中的fs. appendFile之前完成,但第3步中的fs. appendFile在第4步中的fs. appendFile之后完成,因此您将在控制台中的"Outer append"之前看到"Write complete.",而在"Outer append"之后看到"Inner append"。
关键是,你不能依赖Node.js中异步操作的执行顺序,除非你使用某种机制来控制代码流,比如promise、async/await或async库。
例如,使用promise和async/await,你可以重写代码如下:

const fs = require('fs').promises;
const path = require('path');
console.log("Blah blah");
(async () => {
  try {
    await fs.writeFile(path.join(__dirname,'temp.txt'),'Hello!');
    console.log('Write complete.');
    await fs.appendFile(path.join(__dirname,'temp.txt'),'Bye-bye!');
    console.log('Inner append');
    await fs.appendFile(path.join(__dirname,'temp.txt'),'Hi, again!');
    console.log('Outer append');
  } catch (err) {
    console.log(err);
  }
})();

这段代码将始终按顺序记录"Blah blah"、"Write complete."、"Inner append"和"Outer append",因为它使用await关键字等待每个异步操作完成,然后再继续下一个操作。

相关问题