像 Deno 一样,Node.js 现在也逐渐采用 Web 标准 API,包括 Web 标准的 stream、blob 等。其中 Node.js 19+ 引入了一个新的 API fs.openAsBlob
,顾名思义,可以直接从文件路径得到一个 blob。然而这个 API 有几个问题。
首先,这个 API 是异步的,即返回的是Promise<Blob>
。我们知道 Blob 上读取内容的方法如text()
、arrayBuffer()
等本身已经是异步方法,因此返回Promise使用上就略有不便(需要双重 await)。另一方面,fs.openAsBlob
从文档看来是基于文件流的(一旦文件被修改后再调用所返回的 blob 上的方法就会扔 error),stream 本身就是异步的,因此没有必要再包一层异步。
一定要说的话,blob 上有两个属性 type 和 size,可能需要异步计算。但其中 type,即 Blob 的 media type(mime type),一般是通过文件路径的后缀名推测,也可通过openAsBlob
方法的第二个参数指定,所以也不需要异步。唯一问题就是 size。我个人认为,对于本地文件来说,为了获取 size 做稍微一点阻塞(类似于 fs.statSync()
调用)也不是不能接受。另一种可能就是和许多其他方法一样,有异步和同步版本两个对称的 API。
即使说,我们就是为了 size 而要让 openAsBlob
是一个异步方法,那至少这个方法应该在 node:fs/promises
模块中啊, 但实际这个方法是在node:fs
模块中,也就是和一堆 callback 风格方法在一起,这就很令人迷惑了。
还有其他一些问题,比如目前由此 API 产生的 blob 是无法 transfer 到其他 worker 去的(ISSUE 47666),但正常blob是可以的。
此外在目前的@types/node
包里也压根没有该 API —— 不过这也许不是坏事,开发者可能并不应该使用这个还不完善的 API。🫣
注:不过最终我们还是需要类似的 API 的,因为基于底层文件系统的 blob(基于流,而不是直接整个读入内存)是 runtime 才能提供的,自己 polyfill(比如 LazyBlob 库)只能弄出表面 API,但会有很多问题。因为 Blob
的公开构造器并不支持流,而所有平台标准 API 是基于 internal slot/methods 的,平台不暴露出来,就没法自己仿造,自己仿造出来也无法和其他平台 API 一起使用并获得相关能力(比如说前面提到的 transfer 到其他 worker 的能力)。