本文翻译自 How to read files quickly in JavaScript,作者:Daniel Lemire, 略有删改。

假设你需要在服务器上使用JavaScript读取多个文件。在像Node.js这样的运行时环境中,JavaScript有多种读取文件的方式。哪一种是最好的呢?让我们来看看各种方法的测试结果。

使用fs. promise

const fs = require('fs/promises');
const readFile = fs.readFile;
readFile("lipsum.txt", { encoding: 'utf-8' })
  .then((data) => {...})
  .catch((err) => {...})

使用fs.readFile和util.promisify

const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
readFile("lipsum.txt", { encoding: 'utf-8' })  
  .then((data) => {...})
  .catch((err) => {...})

使用fs.readFileSync

const fs = require('fs');
const readFileSync = fs.readFileSync;
var data = readFileSync("lipsum.txt", { encoding: 'utf-8' })

使用await fs.readFileSync

const fs = require('fs');
const readFileSync = fs.readFileSync;
async function f(name, options) {
  return readFileSync(name, options);
}

使用fs.readFile

const fs = require('fs');
const readFile = fs.readFile;
fs.readFile('lipsum.txt', function read(err, data) {...});

测试

我写了一个小型基准测试,用于反复从磁盘读取文件。这是一个简单的循环,每次都会访问相同的文件。我记录了读取文件5万次所需的毫秒数。这个文件相对较小(略超过1千字节)。我使用的是一台拥有数十个Ice Lake Intel核心和大量内存的大型服务器。我使用的Node.js版本是20.1,Bun版本是1.0.14

我多次运行了基准测试,并且在所有情况下都记录了最好的结果。你的结果可能会有所不同。

时间(Node.js) 时间(Bun)
fs.promises 2400 ms 110 ms
fs.readFile和util.promisify 1500 ms 180 ms
fs.readFileSync 140 ms 140 ms
await fs.readFileSync 220 ms 180 ms
fs.readFile 760 ms 90 ms

至少在我的系统上,在这个测试中使用Node.js时,fs.promises比其他方式都要慢的多。在这个测试中Bun比Node.js快得多。

从某种意义上来说,fs.promises 的结果比看上去更差。我发现 readFileSync 使用了 300 毫秒的 CPU 时间,而 fs.promises 却使用了 7 秒的 CPU 时间。这是因为在进行基准测试时,fs.promises 在多个核心上触发了工作。

即使将文件大小增加到32kB,结论也并没有改变。如果你使用更大的文件,许多Node.js案例会因为“堆内存分配失败”而失败。但Bun即使处理大文件也能继续运行。测试结果并没有改变关于Bun的结论:在我的测试中,fs.readFile始终更快,即使对于大文件也是如此。


看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)