JavaScript中讀取文件的各種方法
在JavaScript中,尤其是配合Node.js這樣的運(yùn)行時(shí)環(huán)境,有多種方式可以讀取服務(wù)器上的文件。每種方法都有其適用場(chǎng)景和優(yōu)缺點(diǎn)。今天,我們就來比較幾種常見的文件讀取方法,看看哪一種最適合你的需求。
太長(zhǎng)不看版
如果你在尋找一個(gè)快速且簡(jiǎn)單的方法,fs.promises是一個(gè)不錯(cuò)的選擇,它提供了一個(gè)Promise接口,讓你能夠以現(xiàn)代的異步語法來處理文件讀取。然而,如果你更傾向于同步方法,你可能會(huì)更喜歡fs.readFileSync,雖然它會(huì)阻塞當(dāng)前線程直到文件讀取完成。最后,如果你在尋找一種能夠提供更好的性能的方法,你可能會(huì)想要考慮使用fs.readFile,這是Node.js中最傳統(tǒng)的異步文件讀取方法,使用回調(diào)函數(shù)來處理結(jié)果。
使用fs.promises
const fs = require('fs/promises');
const readFile = fs.readFile;
readFile("lipsum.txt", { encoding: 'utf-8' })
.then((data) => {...})
.catch((err) => {...});這種方法使用了Node.js提供的fs.promises接口,它返回一個(gè)Promise對(duì)象,可以鏈?zhǔn)秸{(diào)用.then()和.catch()方法來處理異步操作的結(jié)果。
使用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) => {...});這種方法通過util.promisify將傳統(tǒng)的回調(diào)函數(shù)轉(zhuǎn)換成返回Promise的函數(shù),使得你可以用更現(xiàn)代的異步語法來處理文件讀取。
使用fs.readFileSync
const fs = require('fs');
const readFileSync = fs.readFileSync;
var data = readFileSync("lipsum.txt", { encoding: 'utf-8' });這是同步方法,它會(huì)阻塞當(dāng)前線程直到文件讀取完成,適用于對(duì)性能要求不高且文件不大的情況。
使用await和fs.readFileSync
const fs = require('fs');
const readFileSync = fs.readFileSync;
async function f(name, options) {
return readFileSync(name, options);
}這種方法結(jié)合了async/await語法和同步讀取,可以在需要同步行為但希望代碼看起來更異步的情況下使用。
使用fs.readFile
const fs = require('fs');
const readFile = fs.readFile;
readFile('lipsum.txt', function read(err, data) {...});這是Node.js中最傳統(tǒng)的異步文件讀取方法,使用回調(diào)函數(shù)來處理結(jié)果。
性能比較
我進(jìn)行了一項(xiàng)小的基準(zhǔn)測(cè)試,重復(fù)讀取磁盤上的同一個(gè)文件,并記錄讀取文件50,000次所需的毫秒數(shù)。文件相對(duì)較小,略多于一千字節(jié)。我使用的是一臺(tái)擁有數(shù)十個(gè)Ice Lake Intel核心和大量?jī)?nèi)存的大型服務(wù)器。測(cè)試使用了Node.js 20.1和Bun 1.0.14。Bun是一個(gè)與Node.js競(jìng)爭(zhēng)的JavaScript運(yùn)行時(shí)[1]。
多次運(yùn)行基準(zhǔn)測(cè)試,我報(bào)告了所有情況下的最佳結(jié)果。你的結(jié)果可能會(huì)有所不同。
方法 | Node.js 時(shí)間 | Bun 時(shí)間 |
fs.promises | 2400 毫秒 | 110 毫秒 |
fs.readFile 和 util.promisify | 1500 毫秒 | 180 毫秒 |
fs.readFileSync | 140 毫秒 | 140 毫秒 |
await fs.readFileSync | 220 毫秒 | 180 毫秒 |
fs.readFile | 760 毫秒 | 90 毫秒 |
至少在我的系統(tǒng)上,在這次測(cè)試中,使用Node.js時(shí)fs.promises明顯比其他方法成本更高。Bun運(yùn)行時(shí)在這次測(cè)試中比Node.js快得多。
結(jié)果看起來對(duì)fs.promises更不利,因?yàn)閞eadFileSync使用了300毫秒的CPU時(shí)間,而fs.promises使用了7秒的CPU時(shí)間。這是因?yàn)閒s.promises在基準(zhǔn)測(cè)試期間觸發(fā)了多個(gè)核心的工作。
將文件大小增加到32kB并不會(huì)改變結(jié)論。如果你使用更大的文件,許多Node.js的案例會(huì)因“堆限制Allocation failed”而失敗。Bun即使在大文件下也能繼續(xù)工作。測(cè)試結(jié)果在Bun中沒有改變結(jié)論:在我的測(cè)試中,即使對(duì)于大文件,fs.readFile也是一致更快的。
本文譯自:https://lemire.me/blog/2024/03/12/how-to-read-files-quickly-in-javascript/
Reference
[1]Bun是一個(gè)與Node.js競(jìng)爭(zhēng)的JavaScript運(yùn)行時(shí): https://bun.dev/






















