等待承诺的 fs.writeFile 与 fs.writeFileSync

Posted

技术标签:

【中文标题】等待承诺的 fs.writeFile 与 fs.writeFileSync【英文标题】:Await promisified fs.writeFile vs fs.writeFileSync 【发布时间】:2019-04-19 15:08:09 【问题描述】:

其中一个选项有什么优点吗?

1.

const fs = require('fs')

const testFunc1 = async () => 
  fs.writeFileSync('text.txt', 'hello world')

2.

const fs = require('fs')
const util = require('util')
const writeFilePromisified = util.promisify(fs.writeFile)

const testFunc2 = async () => 
  await writeFilePromisified('text.txt', 'hello world')

我知道 writeFile 和 writeFileSync 之间的区别。问题是返回 testFunc1 和 testFunc2 的 Promise 之间是否存在一些差异。所以打电话是一样的吗 testFunc1.then(...) // 或等待 testFunc1 要么 testFunc2.then(...) // 或者等待 testFunc2

当文件写入完成时,这两个承诺都将得到满足。

【问题讨论】:

【参考方案1】:
fs.writeFileSync( file, data, options )

fs.writeFile( file, data, options, callback)

异步函数最后一个回调函数 表示异步函数完成的参数。

The ‘fs’ module implements the File I/O operation. Methods in the fs module can be synchronous as well as asynchronous. 

开发人员更喜欢异步方法而不是同步方法,因为他们在程序执行期间从不阻塞程序,而后者会阻塞。在 Node.js 中阻塞主线程是“ma​​lpractice”,因此同步函数只能用于“debugging”或没有其他选项可用时。

fs.writeFileSync() 是一种同步方法,如果出现则创建一个新文件 指定的文件不存在,而 fs.writeFile() 是 异步方法。

【讨论】:

【参考方案2】:

fs 已经包含不需要promisify 的promisified API。

const fsPromises = require("fs/promises");
await fsPromises.writeFile(file, data[, options])

基于 Promise 的异步版本需要将其用作基于 Promise 的控制流的一部分,而同步版本不强制此要求。

异步 ​​readFile/writeFile 是非阻塞的,而同步 readFileSync/writeFileSync 是阻塞的,但可以更快地完成作业。这在密集的 IO 操作期间可能会很明显。

【讨论】:

fs.promise API 对于节点 10 是实验性的。 请您解释一下返回 testFunc1 和 testFunc2 的两个 Promises 之间的区别。我可以看到那里没有差异。 testFunc1() 没用。它不会从承诺中受益。它阻塞了主线程,因为writeFileSync 是同步的。如果得到的承诺是awaited,则提供一个微小的延迟。【参考方案3】:

writeFile() 和 writeFileSync() 之间的区别正如其他 writeFileSync() “阻塞”所解释的那样。那么,“阻塞”和“不阻塞”有什么区别呢?

我写了一个小测试,比较了 writeFile() 和 writeFileSync() 的速度。我测量了 writeFileSync() 返回结果所用的时间与从调用 writeFile() 到调用其回调参数所用的时间。令我(最初)惊讶的是,两者之间没有明显的区别。 writeFile() 似乎并不比 writeFileSync() 快。那么,当它似乎使我的程序流程复杂化时,我为什么要使用它呢?

但是,如果我不等待它的回调参数被调用,我测量了 writeFile() 所花费的时间。速度有很大差异,可能是 10 倍。

因此差别很大或没有差别取决于程序的其余部分。如果您对 writeFileSync() 的调用需要很长时间,那么您的程序在等待 writeFileSync() 返回时将无能为力。如果您执行 writeFile() 并在执行其他任何操作之前等待回调完成,则结果没有什么不同。但是如果你不(不需要)等待它的回调被调用,writeFile() 会快得多。

如果您编写某种调用 writeFileSync() 的服务器,这将有很大的不同。服务器在等待 writeFileSync() 完成时无法为任何新请求提供服务。如果大多数请求导致调用 writeFileSync(),这可能会对您的服务器性能产生重大影响。

【讨论】:

【参考方案4】:

为了说明两个返回函数的promise之间的区别:

const fs = require('fs')
const util = require('util')

const testFunc1 = async () => 
  fs.writeFileSync('text.txt', 'hello world')
  console.log('file write done with writeFileSync')


const writeFilePromisified = util.promisify(fs.writeFile)

const testFunc2 = async () => 
  await writeFilePromisified('text.txt', 'hello world')
  console.log('file write done with promisified writeFile')


console.log('start test1')
testFunc1().then(() => 
  console.log('promise 1 is fullfiled')
)
console.log('start test2')
testFunc2().then(() => 
  console.log('promise 2 is fullfiled')
)
console.log('stop')

输出将是:

start test1
file write done with writeFileSync
start test2
stop
promise 1 is fullfiled
file write done with promisified writeFile
promise 2 is fullfiled

所以就像 estus 所说的 testFunc1 阻止了主线程的执行。 testFunc2 不阻塞。

【讨论】:

【参考方案5】:

fs.readFile 采用回调函数,这意味着它不会阻止脚本的执行。 fs.readFileSync 但是 接受回调,这意味着脚本的执行将暂停,直到进程完成。 使用 promisfy 是解决此问题的一种方法,对于小文件它不会产生影响,但对于大文件,您可能希望将 fs.readFileSync 转换为 Promise,这样您就不会阻止执行。 希望对您有所帮助。

【讨论】:

以上是关于等待承诺的 fs.writeFile 与 fs.writeFileSync的主要内容,如果未能解决你的问题,请参考以下文章

fs.writeFile 没有错误,但是写入文件失败

不写入 JSON 文件。 fs.writeFile 不工作

为啥节点 10 强制在 fs.writeFile() 上传递回调?

如何使用 fs.writefile 创建 HTML 文件

在 fs.writeFile([option]) 中,“选项参数”通常如何工作?

nodejs模块——fs模块 WriteFile写入文件