大佬看看这个代码会怎么样
发布于 5 年前 作者 jacksparrow68 3568 次浏览 来自 问答
const fs = require('fs');
function writeFile() {
    fs.writeFile('a.txt', 'aaaaaa', { flag: 'a' }, err => {
        if (err) return console.log(err);
        console.log('----ok----');
    });
}
function name() {
    writeFile();
    while (1) { }
}
name();
11 回复
  1. 创建文件,写入hello, 打印-----ok-----;
  2. 创建文件,不写hello;
  3. 不创建文件,不打印; 会是哪一种情况?为什么?

应该是:2. 创建文件,不写hello;

首先肯定会创建文件,所以排除 3,因为是按顺序执行的,只有写入操作是异步的。

那到底能不能写入内容呢,如果瞎猜的话,肯定是猜写不进去。最初我也是猜的。原因就是 fs.writeFile 如果传入第一个参数是 string,肯定要经历很多对用户不可见的步骤。

我实际运行了一下,确实是 2。

看了源码,https://github.com/nodejs/node/blob/master/lib/fs.js#L1174-L1199

我加了注释

function writeFile(path, data, options, callback) {
  callback = maybeCallback(callback || options);
  options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
  const flag = options.flag || 'w';

// 【判断是否为文件描述符】
// 【很显然,这道题里的 path 不是文件描述符,而是普通字符串,作为目录】
  if (isFd(path)) {
    writeFd(path, true);
    return;
  }

  // 【调用 fs.open 打开文件,此时文件不存在,因此创建了文件】
  fs.open(path, flag, options.mode, (openErr, fd) => {
  	// 【成功打开文件后,写入内容】        ⬆️
	// 【此操作是**异步**的】
    if (openErr) {
      callback(openErr);
    } else {
      writeFd(fd, false);
    }
  });
}

@justjavac 哦哦,看到fs.open也是异步的呢,为什么不在fs.open那儿就停下?

我的想法是这样:写文件操作会交给线程池处理,处理完了后会进入任务队列里排队直到主线程空闲执行回调函数。所以和这里的现象不相符,按照我的理解应该是"创建文件,写入hello, 不打印"。

@jacksparrow68 fs.open 创建了文件。但是写入内容实在 open 的回掉函数里面

把循环换成 process.exit() 效果是一样的

@jacksparrow68 open 是异步函数,不代表走到 open 的位置就得停下,open 内部也有同步操作的

https://github.com/nodejs/node/blob/master/lib/fs.js#L412-L435

@lanlonggang 就是因为 open 没有停下所有才新建了文件啊。打开(新建)文件的操作是同步的,但是写入内容的操作是异步的。

@lanlonggang 你把我都绕晕了,正在下载 node 源码,准备编译调试一下。我看源码的理解,fs.writeFile 是异步的,fs.open 是异步的。fs.writeFile 执行了,fs.open 也执行了,但是 fs.writeFilecallback 没有执行,fs.opencallback 也没有执行。

@justjavac 嗯。 10楼好像可以解释得通了。open的callback放到任务队列里等待主线程空闲才会执行writeFd。所以文件是有了也打开了,但是主线程没空。

回到顶部