自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

fsx 簡介:適用于 JavaScript 的現(xiàn)代文件系統(tǒng) API

開發(fā) 前端
JavaScript 運(yùn)行時中的文件系統(tǒng) API 已經(jīng)很久沒有這么好了,這是我試圖做出一個更好的文件系統(tǒng) API 的嘗試。

JavaScript 運(yùn)行時中的文件系統(tǒng) API 已經(jīng)很久沒有這么好了,這是我試圖做出一個更好的文件系統(tǒng) API 的嘗試。

我們今天擁有的 JavaScript API 比十年前要好得多。考慮一下從 XMLHttpRequest 到 fetch()的轉(zhuǎn)變:開發(fā)者體驗(yàn)顯著改善,允許我們編寫更簡潔、功能性更強(qiáng)的代碼來完成同樣的事情。異步編程的 promises 的引入允許了這種變化,以及一系列其他變化,使得 JavaScript 更容易編寫。然而,有一個領(lǐng)域幾乎沒有創(chuàng)新:服務(wù)器端 JavaScript 運(yùn)行時的文件系統(tǒng) API。

Node.js:當(dāng)今文件系統(tǒng) API 的起源

Node.js 最初發(fā)布于 2009 年,隨之誕生了 fs 模塊。fs 模塊是圍繞 Linux 的核心實(shí)用程序構(gòu)建的,其中的許多方法都反映了它們的 Linux 靈感,如 rmdir 、 mkdir 和 stat 。為此,Node.js 成功創(chuàng)建了一個低級文件系統(tǒng) API,可以處理開發(fā)人員希望在命令行上完成的任何事情。不幸的是,這就是創(chuàng)新的終點(diǎn)。

Node.js 文件系統(tǒng) API 最大的改變是引入了 fs/promises ,將整個實(shí)用程序從基于回調(diào)的方法移動到基于 promise 的方法。較小的增量變化包括實(shí)現(xiàn) web 流和確保 reader 也實(shí)現(xiàn)了異步迭代器。該 API 仍然使用專有的 Buffer 類來讀取二進(jìn)制數(shù)據(jù)。(盡管 Buffer 現(xiàn)在是 Uint8Array 的子類,但仍然存在不兼容性,這使得使用 Buffers 有問題。)

即使是 Ryan Dhal 在 Node.js 上的繼任者 Deno,也沒有在文件系統(tǒng) API 上做太多的改進(jìn),它基本上遵循了與 Node.js 中的 fs 模塊相同的模式,盡管它使用了 Uint8Arrays,而 Node.js 使用了 Buffer s,并且在不同的地方使用了異步迭代器,但它仍然采用了與 Node.js 相同的低級 API 方法。

只有 Bun,作為服務(wù)器端 JavaScript 運(yùn)行時生態(tài)系統(tǒng)的最新成員,甚至嘗試使用 Bun.file() 來更新文件系統(tǒng) API,這是受 fetch() 的啟發(fā)。雖然我贊賞這種對如何使用文件的重新思考,但當(dāng)你處理多個文件時,為每個想要處理的文件創(chuàng)建一個新對象可能會很麻煩(當(dāng)處理數(shù)千個文件時,會有一個巨大的性能損失)。除此之外,Bun 希望你使用 Node.js fs 模塊進(jìn)行其他操作。

一個現(xiàn)代的文件系統(tǒng) API 會是什么樣子?

在花費(fèi)數(shù)年時間在維護(hù) ESLint 的同時與 Node.js fs 模塊斗爭之后,我問自己,一個現(xiàn)代的文件系統(tǒng) API 會是什么樣子?

  • 通常情況下會很簡單。至少 80%的時間,我不是讀取文件就是寫入文件,或者檢查文件是否存在,差不多就是這樣,然而這些操作充滿了危險,因?yàn)槲倚枰獧z查各種東西以避免錯誤或記住額外的屬性(例如 { encoding: "utf8" } )。
  • 錯誤將很少發(fā)生。我對 fs 模塊最大的抱怨就是它拋出錯誤的頻率。在不存在的文件上調(diào)用 fs.stat() 會拋出錯誤,這意味著你實(shí)際上需要將每個調(diào)用包裝在 try-catch 中。為什么?對于大多數(shù)應(yīng)用程序來說,缺少文件并不是不可恢復(fù)的錯誤。
  • 行動將是可觀察的。在測試文件系統(tǒng)操作時,我真的只是想要一種方法來驗(yàn)證我期望發(fā)生的事情是否確實(shí)發(fā)生了。我不想與其他一些實(shí)用程序建立間諜網(wǎng)絡(luò),這些實(shí)用程序可能會也可能不會改變我正在觀察的方法的實(shí)際行為。
  • 模擬很容易。我總是驚訝于模擬文件系統(tǒng)操作的難度。最后我只能使用 proxyquire 之類的東西,否則就需要設(shè)置迷宮般的模擬,花上一段時間才能弄好。對于文件系統(tǒng)操作來說,這是一個很常見的需求,竟然還沒有解決方案。

帶著這些想法,我開始設(shè)計(jì) fsx。

FSX 基礎(chǔ)知識

fsx庫是我圍繞現(xiàn)代高級文件系統(tǒng) API 應(yīng)該是什么樣子的想法的結(jié)晶。在這一點(diǎn)上,它專注于支持最常見的文件系統(tǒng)操作,而把較少使用的操作(例如 chmod )拋在后面。(我并不是說這些操作在將來不會被添加,但對我來說,從最常見的情況開始,然后以與初始方法相同的謹(jǐn)慎方式構(gòu)建更多的功能是很重要的。)

使用 fsx 運(yùn)行時包

首先,fsx API 在三個運(yùn)行時包中可用。這些包都包含相同的功能,但綁定到不同的底層 API。這些包是:

  • fsx-node - Node.js 中 fsx API 的綁定
  • fsx-deno - fsx API 的 Deno 綁定
  • fsx-memory - 適用于任何運(yùn)行時(包括 web 瀏覽器)的內(nèi)存實(shí)現(xiàn)

所以,開始時,你需要使用最適合你用例的運(yùn)行時包。為了本文的目的,我將專注于 fsx-node ,但相同的 API 存在于所有運(yùn)行時包中. 所有運(yùn)行時包都導(dǎo)出一個 fsx 單例,你可以以類似于 fs的方式使用它。

import { fsx } from "node-fsx";

使用 fsx 讀取文件

文件是通過使用返回特定數(shù)據(jù)類型的方法來讀取的:

  • fsx.text(filePath) 讀取給定的文件并返回一個字符串。
  • fsx.json(filePath) 讀取給定的文件并返回一個 JSON 值。
  • fsx.arrayBuffer(filePath) 讀取給定的文件并返回一個 ArrayBuffer 。

這里有一些例子:

// read plain text
const text = await fsx.text("/path/to/file.txt");

// read JSON
const json = await fsx.json("/path/to/file.json");

// read bytes
const bytes = await fsx.arrayBuffer("/path/to/file.png");

如果文件不存在,每個方法都會返回 undefined 而不是拋出錯誤。這意味著您可以使用 if 語句而不是 try-catch,并且可以選擇使用 nullish 合并運(yùn)算符來指定默認(rèn)值,如下所示:

// read plain text
const text = (await fsx.text("/path/to/file.txt")) ?? "default value";

// read JSON
const json = (await fsx.json("/path/to/file.json")) ?? {};

// read bytes
const bytes =
  (await fsx.arrayBuffer("/path/to/file.png")) ?? new ArrayBuffer(16);

我覺得這種方法在 2024 年比不斷擔(dān)心不存在的文件出錯更有 JavaScript 風(fēng)格。

使用 fsx 寫文件

要寫文件,調(diào)用 fsx.write() 方法。這個方法接受兩個參數(shù):

  • filePath:string - 寫入的路徑
  • value:string|ArrayBuffer - 寫入文件的值

這里有一個例子:

// write a string
await fsx.write("/path/to/file.txt", "Hello world!");

const bytes = new TextEncoder().encode("Hello world!").buffer;

// write a buffer
await fsx.write("/path/to/file.txt", buffer);

作為額外的好處,fsx.write() 將自動創(chuàng)建任何尚不存在的目錄。這是我經(jīng)常遇到的另一個問題,我認(rèn)為它應(yīng)該在現(xiàn)代文件系統(tǒng) API 中“正常工作”。

使用 fsx 檢測文件

要確定一個文件是否存在,使用 fsx.isFile(filePath) 方法,如果給定的文件存在,則返回 true ,否則返回 false 。

if (await fsx.isFile("/path/to/file.txt")) {
  // handle the file
}

與 fs.stat() 不同,如果文件不存在,這個方法會返回 false ,而不是拋出錯誤。

try {
  const stat = await fs.stat(filePath);
  return stat.isFile();
} catch (ex) {
  if (ex.code === "ENOENT") {
    return false;
  }

  throw ex;
}

刪除文件和目錄

fsx.delete() 方法接受一個參數(shù),即要刪除的路徑,并且對文件和目錄都有效。

// delete a file
await fsx.delete("/path/to/file.txt");

// delete a directory
await fsx.delete("/path/to");

fsx.delete() 方法故意過于激進(jìn):它會遞歸地刪除目錄,即使它們不是空的(實(shí)際上是 rmdir -r)。

fsx 日志

fsx 的一個關(guān)鍵特性是,由于其內(nèi)置的日志系統(tǒng),很容易確定哪些方法被調(diào)用,并使用了哪些參數(shù)。要啟用 fsx 實(shí)例的日志記錄,請調(diào)用 logStart() 方法并傳入一個日志名稱。當(dāng)你完成日志記錄時,請調(diào)用 logEnd() 并傳入相同的名稱來檢索日志條目的數(shù)組。

fsx.logStart("test1");

const fileFound = await fsx.isFile("/path/to/file.txt");

const logs = fsx.logEnd("test1");

每個日志條目都是一個包含以下屬性的對象:

  • timestamp - 創(chuàng)建日志的數(shù)字時間戳
  • type - 描述日志類型的字符串
  • data - 與日志相關(guān)的附加數(shù)據(jù)

對于方法調(diào)用,日志條目的 type 是 call ,而 data 屬性是一個對象,包含:

  • methodName - 被調(diào)用的方法的名稱
  • args - 傳遞給方法的參數(shù)數(shù)組。

對于前面的例子, logs 將包含一個條目:

// example log entry

{
    timestamp: 123456789,
    type: "call",
    data: {
        methodName: "isFile",
        args: ["/path/to/file.txt"]
    }
}

了解這一點(diǎn)后,您可以輕松地在測試中設(shè)置日志記錄,然后檢查調(diào)用了哪些方法,而無需使用第三方間諜庫。

使用 fsx impls

fsx 的設(shè)計(jì)是這樣的,抽象的核心功能包含在 fsx-core 包中,每個運(yùn)行時包都擴(kuò)展了該功能,使用特定于運(yùn)行時的文件系統(tǒng)操作實(shí)現(xiàn),這些操作被包裝在一個稱為 impl 的對象中。

  1. fsx 單例
  2. 一個構(gòu)造函數(shù),可以創(chuàng)建 fsx 的另一個實(shí)例(比如 fsx-node 中的 NodeFsx )
  3. 一個構(gòu)造函數(shù),可以創(chuàng)建運(yùn)行時包的 impl 實(shí)例(如 node-fsx 中的 NodeFsxImpl )。

這可以讓您只使用所需的功能。

fsx 中的 base impls 和 active impls

每個 fsx 實(shí)例都有一個 base 類實(shí)現(xiàn),它定義了 fsx 對象在生產(chǎn)環(huán)境中的行為。active impls 是在任何給定時間使用的實(shí)現(xiàn),它可能也是 base 類實(shí)現(xiàn),也可能不是。你可以調(diào)用 fsx.setImpl()來改變 active impls。

import { fsx } from "fsx-node";

fsx.setImpl({
  json() {
    throw Error("This operation is not supported");
  },
});

// somewhere else

await fsx.json("/path/to/file.json"); // throws error

在此示例中,基本實(shí)現(xiàn)被替換為自定義實(shí)現(xiàn),該自定義實(shí)現(xiàn)在調(diào)用 fsx.json() 方法時會引發(fā)錯誤。這使得您可以輕松地模擬測試方法,而不必?fù)?dān)心它可能如何影響整個包含的 fsx 對象。

交換 impls 進(jìn)行測試

假設(shè)你有一個名為 readConfigFile() 的函數(shù),它使用了來自 node-fsx 的 fsx 單例來讀取名為 config.json 的文件,當(dāng)測試這個函數(shù)時,你不想讓它實(shí)際訪問文件系統(tǒng),你可以把 fsx 的實(shí)現(xiàn)換成 fsx-memory 提供的內(nèi)存文件系統(tǒng)實(shí)現(xiàn),如下:

import { fsx } from "fsx-node";
import { MemoryFsxImpl } from "fsx-memory";
import { readConfigFile } from "../src/example.js";
import assert from "node:assert";

describe("readConfigFile()", () => {

    beforeEach(() => {
        fsx.setImpl(new MemoryFsxImpl());
    });

    afterEach(() => {
        fsx.resetImpl();
    });

    it("should read config file", async () => {

        await fsx.write("config.json", JSON.stringify({ found: true });

        const result = await readConfigFile();

        assert.isTrue(result.found);
    });

});

這就是使用 fsx 在內(nèi)存中模擬整個文件系統(tǒng)是多么容易。您不必像模塊加載器攔截那樣擔(dān)心導(dǎo)入所有測試模塊的順序,也不需要經(jīng)歷包含模擬庫的過程以確保一切正常。您只需更換測試的 impl,然后再重置它。通過這種方式,您可以以更高性能且不易出錯的方式測試文件系統(tǒng)操作。

命名注意事項(xiàng)

不幸的是,在我發(fā)布 fsx 的時候,亞馬遜發(fā)布了一款名為 FSx[2] 的產(chǎn)品。如果它獲得任何支持,我可能會重命名這個庫,歡迎提出建議。

希望得到結(jié)論和反饋

長期以來,我們一直在使用 JavaScript 運(yùn)行時中笨拙的低級文件系統(tǒng) API。fsx 庫是我嘗試重新想象現(xiàn)代文件系統(tǒng) API 的樣子,如果我們花一些時間關(guān)注最常見的情況,并改進(jìn) JavaScript 語言目前提供的人體工學(xué)設(shè)計(jì)。通過從頭開始重新思考,我認(rèn)為 fsx 為我們提供了一種更愉快的文件系統(tǒng)體驗(yàn)。

基礎(chǔ)庫只關(guān)注我最常用的方法,但我計(jì)劃在了解和思考用例后添加更多方法。您今天就可以試用,歡迎反饋。我很想知道你的想法!

責(zé)任編輯:華軒 來源: 獨(dú)立開發(fā)者張張
相關(guān)推薦

2021-03-18 10:46:00

Linux監(jiān)控工具命令

2018-10-24 10:43:13

2022-03-14 08:00:00

KoolKits工具開發(fā)

2009-11-29 17:10:01

NetgearLinux系統(tǒng)路由器

2010-04-30 15:51:48

Unix系統(tǒng)

2022-11-17 10:45:46

Linux文件備份系統(tǒng)

2011-12-08 09:43:56

虛擬化vmwareVMware Fusi

2023-11-30 08:55:15

LinuxLibreOffic

2019-08-15 15:48:30

Linux系統(tǒng)軟件

2020-05-14 17:54:54

查看器 Linux 系統(tǒng)

2022-09-02 17:47:46

Linux筆記應(yīng)用

2012-09-12 14:40:19

Lustre文件系統(tǒng)

2020-10-10 09:19:58

JavaScript開發(fā)技術(shù)

2018-01-09 11:09:42

RESTSOAP開源

2019-08-23 11:00:00

云計(jì)算網(wǎng)絡(luò)安全

2023-03-08 12:35:59

綜合布線

2021-11-03 10:14:31

PowerEdge

2011-05-13 09:56:23

Ubuntu 11.0

2013-02-21 10:13:25

2021-12-13 12:56:26

Linux瀏覽器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號