简体   繁体   English

Node.js fs.writeFile() 似乎不是异步的

[英]Node.js fs.writeFile() doesn't seem asynchronous

If we head over to the documentation of Node.js for the fs.writeFile() method , we see that it is asynchronous in nature.如果我们查看fs.writeFile()方法的 Node.js 文档,我们会发现它本质上是异步的。

Now, with that in mind, I set up the following code to test this idea:现在,考虑到这一点,我设置了以下代码来测试这个想法:

const fs = require('fs');

function sync(delay) {
    const startingTime = new Date();
    while ((new Date() - startingTime) < delay) {
        // keep this loop going
    }
}


fs.writeFile(__dirname + '/hello.txt', 'Hello World', function() {});

sync(4000);

I have opened the hello.txt file in VSCode, and whenever some data is written to the file, VSCode shows it live.我在 VSCode 中打开了hello.txt文件,每当有数据写入该文件时,VSCode 就会实时显示。

I expect this code to write Hello World to the file hello.txt , before 4 seconds (which is the delay caused by sync(4000) ) since fs.writeFile() is asynchronous in nature (as the documentation says).我希望此代码将Hello World写入文件hello.txt ,在 4 秒之前(这是由sync(4000)引起的延迟),因为fs.writeFile()本质上是异步的(如文档所述)。 However, to my surprise, any data is written to the file after 4 seconds.然而,令我惊讶的是,任何数据都会在 4 秒写入文件。

This doesn't seem asynchronous at all!这似乎根本不是异步的!

My question is, why isn't the data written to the file hello.txt before the synchronous execution of the whole script.我的问题是,为什么没有在整个脚本同步执行之前将数据写入文件hello.txt

I suspect (btw, I don't know much about OS threads) that when fs.writeFile() is called, it writes to the file asynchronously (without blocking the main thread) on another OS thread that is free, but this doesn't seem to happen.我怀疑(顺便说一句,我对操作系统线程了解不多)当fs.writeFile()时,它会在另一个空闲的操作系统线程上异步写入文件(不阻塞主线程),但这不会似乎没有发生。

I have been testing quite a lot other things related to file-write utilities, such as Writable streams and have seen the same issue.我一直在测试很多与文件写入实用程序相关的其他东西,例如可写流,并且遇到了同样的问题。 Nothing is written unless and until all of the synchronous execution completes.除非并直到所有同步执行完成,否则不会写入任何内容。

I need a clear explanation on this kind-of internal thing.我需要对这种内部事物有一个明确的解释。

Try this:尝试这个:

import { writeFile } from 'fs/promises'

function sync(delay) {
  const startingTime = new Date();
  while ((new Date() - startingTime) < delay) {
      // keep this loop going
  }
}

(async () => {
  await writeFile(__dirname + '/hello.txt', 'Hello World');

  sync(4000)
})();

Although writeFile may seem asynchronous in behavior, NodeJS is limited by the fact that JavaScript is a single-threaded language.尽管writeFile在行为上可能看起来是异步的,但 NodeJS 受到 JavaScript 是单线程语言这一事实的限制。 To simulate being asynchronous, NodeJS uses the event loop in order to process actions.为了模拟异步,NodeJS 使用事件循环来处理操作。

I'm not sure exactly on the inner workings of the writeFile function, but judging from how the code runs it can be assumed that 3 or more tasks are being added to the event loop (one for creating the file, one for writing to the created file, and one for processing the callback).我不确定writeFile function 的内部工作原理,但从代码的运行方式来看,可以假设 3 个或更多任务被添加到事件循环中(一个用于创建文件,一个用于写入创建的文件,一个用于处理回调)。 The multiple events are important to understanding why the code executes the way it does.多个事件对于理解代码执行方式的原因很重要。

When the writeFile function call executes, the 'hello.txt' file is generated empty (creating the file, the first task).writeFile function 调用执行时,'hello.txt' 文件生成为空(创建文件,第一个任务)。 However, since the writeFile call was executed, the JavaScript engine has already moved on and executed the culprit of the problem, your sync function. The sync function utilizing a while loop to simulate a delay rather than the normally used setTimeout function is key to understanding what is going on internally.但是,由于执行了writeFile调用,JavaScript 引擎已经继续执行并执行了问题的罪魁祸首,您的sync function。 sync function 使用while循环来模拟延迟而不是通常使用的setTimeout function 是理解的关键内部发生了什么。

What the while loop is doing in this scenario is hijacking the event loop before writing to the file that was created (which explains why the file is created but not written to) due to while being a blocking operation. while 循环在这种情况下所做的是在写入创建的文件之前劫持事件循环(这解释了为什么创建文件但不写入文件),因为while是一个阻塞操作。 You can verify this behavior by adding another I/O operation using writeFileSync before your sync function. Both files will be created but only the writeFileSync function's file would have anything written in it.您可以通过在sync function 之前使用writeFileSync添加另一个 I/O 操作来验证此行为。将创建两个文件,但只有writeFileSync函数的文件会写入任何内容。

Due to the while loop blocking the event loop, the data is written to the file after your delay because that is when the while loop finishes executing and frees up the event loop in order to execute the final tasks of the writeFile function.由于while循环阻塞了事件循环,数据在您的延迟后写入文件,因为那是while循环完成执行并释放事件循环以执行writeFile function 的最终任务的时间。

Note: This answer was written with a degree of uncertainty as I haven't explored the internals of how the NodeJS event loop works thoroughly.注意:这个答案是在一定程度上不确定的,因为我还没有探索 NodeJS 事件循环如何彻底工作的内部结构。 The documents I referenced in answering this question are here:我在回答这个问题时引用的文件在这里:

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

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