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();
- 创建文件,写入hello, 打印-----ok-----;
- 创建文件,不写hello;
- 不创建文件,不打印; 会是哪一种情况?为什么?
应该是: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 没有停下所有才新建了文件啊。打开(新建)文件的操作是同步的,但是写入内容的操作是异步的。
@justjavac 回复三楼的。
@lanlonggang 你把我都绕晕了,正在下载 node 源码,准备编译调试一下。我看源码的理解,fs.writeFile
是异步的,fs.open
是异步的。fs.writeFile
执行了,fs.open
也执行了,但是 fs.writeFile
的 callback
没有执行,fs.open
的 callback
也没有执行。
@justjavac 嗯。 10楼好像可以解释得通了。open的callback放到任务队列里等待主线程空闲才会执行writeFd。所以文件是有了也打开了,但是主线程没空。