fetch函数
撰写时间:2024-12-25
修订时间:2025-02-27
fetch函数用于加载特定资源,返回一个注入了Response实例的Promise对象。
Response基本属性
其中,body属性所返回的ReadableStream,可参见Stream一节。
资源种类
由于要加载的资源可能不存在,因此必要时可检查response的ok属性。但许多时候,如果我们确信要加载的特定资源必然存在,则此步往往可以省略。
response的text方法返回一个注入文本的Promise对象,因此可用于Promise串联。下面集中列出了Response所支持的加载各类资源的方法:
- arrayBuffer
- 返回ArrayBuffer实例。
- blob
- 返回Blob实例。
- bytes
- 返回Uint8Array实例。
- formData
- 返回FormData实例。
- json
- 返回JSON实例。
- text
- 返回文本。
加载各类资源
加载文本文件
Response的text方法返回注入文本内容的Promise。
加载了一个名为text.txt的文件,并打印出了加载文件后所提取出的文本的内容。
Bytes
加载文本文件,显示字节
Response的bytes方法返回注入Uint8Array的Promise。
各浏览器对bytes方法的支持因高低版本而有异。因此上面的代码在低版本的浏览器中运行时,可能会抛出异常。若是这种情况,最后一行代码确保捕获异常后供PageConsole输出异常信息。
我简直不敢相信自己的眼睛,本章最初撰写时间为2024年12月25日,当时Chrome尚未支持bytes方法。但仅在2025年1月24日,Chrome升级到132版本后就开始支持该方法了。因此,尽可放心调用该函数了。由衷感谢这些大厂的及时技术更新,让开发人员不再左右为难。
与上节相比,都是加载了同一个文本文件,但为何这次显示数字而不是文本?难道文本文件中存储的不是字符串吗?
文本文件的本质
令我们想不到的是,就连日常使用得最多、司空见惯的文本文件,都暗藏众多玄机。
一句话,文本文件中保存的不是字符串,而是字符串经编码后的编码值。
fetch返回被注入的Response,Response的body属性,将所加载文件的最原始的数据,存储在一个ReadableStream,也即一个可读取数据的流中。
上面的代码,将读取到的原始数据,通过管道操作,原封不动地传输到一个只负责打印数值的WritableStream(也即可改写的流)中,我们得以看到原汁原味的结果。(具体细节,请参见Stream一章,这里只需知道该代码可读出原始数据就行了。)
我是在NetBeans中创建text.txt文件的,其默认使用了UTF-8的编码,因此,在保存文件时,NetBeans自动将相应字符串的UTF-8的编码值保存进文件中。而当我们通过流的方式来读取出来时,将直接显示这些编码值,而不是将这些编码值解码后所得到的字符串。
而如果我们使用任何一款支持UTF-8编码的文本编辑器打开上述文件时,文本编辑器默默地将这些UTF-8编码解码为我们看得懂的字符串。而上一节中的response.text()
所干的就是同样的解码工作。
因此,Response的body属性存储原始编码值数据,而其text方法将原始编码值数据解码为文本格式,bytes方法将原始编码值数据解码为Uint8Array格式。
故此,文本文件存储的是按诸如ASCII, UTF-8等特定编码格式而编码后的编码值,而非我们想当然的字符串。
文本文件与二进制文件的异同
文本文件与二进制文件相同的地方在于,它们都是以字节为单位存储了整数的数值。
它们不同的地方在于:
- 存储文件时的编码方式不同。文本文件按诸如ASCII, UTF-8, UTF-16, UTF-32, GB 2312等方式来编码。而二进制文件则按更多的方式来编码,如.png编码方式、.exe编码方式、.wasm编码方式等等。
- 文本文件的编码值一般可以还原为可打印字符;而二进制文件的编码值无需考虑是否为可打印字符,它可以存储为任意字节。因此,若用文本编辑器按文本进行解码来打开文件,则因被解码为不可打印的字符而看到一大堆
乱码
。 乱码
是特定解码方式下的无效字符,但并不等于乱码
是无效数据。使用何种方式来编码,就应使用相对应的解码来还原它,就不会再出现乱码
。一般通过各类文件的文件扩展名来提供默认解码的依据。
作为例子,下面是一个多信息文本文件的内容:
尽管它也是一个文本文件,但还以可打印文本的方式,存储了文本字体、段落、颜色等其他额外信息。这样,当使用支持这种格式的文本编辑器,如Mac OS X下的文本编辑应用软件等,来打开该文件时,则可看到并编辑丰富多彩的文本格式。可以说,它就是一个小型的.doc文件。
Response各种方法的意义
综上,Response的body存储了原始的字节数据,而其诸如text, bytes, arrayBuffer等方法,不过是应用了不同的解码方式后所得到的不同结果而已。
ArrayBuffer
Response的arrayBuffer方法返回注入ArrayBuffer的Promise。
运行下面代码:
第一步,先创建一个Float32Array对象,并将其值初始化为[0.1, 0.2, 0.3]。
第二步,将其内容创建为一个URL。该URL可视为一个二进制文件。
第三步,加载该URL,解码为ArrayBuffer,并以Float32Array的视图来显示该数据。其值为[0.10, 0.20, 0.30],与我们在第一步中所使用的数值一致。接着,再次加载该资源,这次使用Uint8Array的方式来查看,这就是二进制文件的原始数值。
第四步,释放资源。
上面的第三步也可改写为使用流的方式来查看:
具体参见ArrayBuffer一章。
Blob
Response的blob方法返回注入Blob的Promise。
Blob的方法中,其text, arrayBuffer, bytes等方法与Response相对应的方法一样。此外,Blob的stream方法还可像Response.body一样,返回一个ReadableStream实例。
而Blob更大的价值在于,正如上面所见,可以将其作为参数传给URL的createObjectURL方法,从而创建出一个可供其他对象引用的URL,这是Response获取资源的其他方法都不具备的优势。
JSON
Response的json方法返回注入JSON对象的Promise。