引言
在 Web 应用 开发中,网络请求是前端开发的重要组成部分。随着技术的不断进步,fetch
API 作为一种新兴的网络请求方式,逐渐取代了传统的 XMLHttpRequest
(XHR)和第三方库 axios
。
概念
fetch
是一个用于访问和操纵 HTTP 管道的部分(包括响应)的 JavaScript API。它返回一个 Promise
,可以处理异步操作,使得代码更加简洁和现代化。
核心概念
- Resource: 需要获取的资源,可以是一个 URL 或者一个
Request
对象。 - Request: 描述请求的配置对象,包括 URL、方法、头部信息等。
- Response: 描述响应的配置对象,包括状态码、头部信息和响应体。
使用方法
基本请求
fetch("https://api.example.com/data")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
在这个例子中,我们使用 fetch
发起一个 GET 请求,并处理返回的 JSON 数据。
带参数的请求
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ key: "value" }),
};
fetch("https://api.example.com/data", requestOptions)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
在这个例子中,我们使用 fetch
发起一个 POST 请求,并发送 JSON 数据。
流式请求与非流式请求
非流式请求
非流式请求是指整个请求和响应过程是完整的,适用于数据量较小的情况。
fetch("https://api.example.com/small-data")
.then((response) => response.json())
.then((data) => console.log(data));
在这个例子中,我们使用 fetch
发起一个 GET 请求,并处理返回的 JSON 数据。
流式请求
流式请求允许数据分块传输,适用于数据量较大的情况,可以提高性能和响应速度。
fetch("https://api.example.com/large-data").then((response) => {
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
reader.read().then(function processText({ done, value }) {
if (done) {
console.log("Stream is complete");
return;
}
const chunk = decoder.decode(value, { stream: true });
console.log("Received chunk:", chunk);
return reader.read().then(processText);
});
});
在这个例子中,我们使用 fetch
发起一个 GET 请求,并处理返回的流式数据。
fetch 与 XHR、axios 的区别
fetch vs XHR
- 语法:
fetch
使用 Promise,语法更简洁;XHR
使用回调函数,代码较复杂。 - 错误处理:
fetch
只在网络错误时拒绝 Promise,HTTP 错误状态(如 404)不会导致拒绝;XHR
在任何错误时都会调用onerror
。 - 流处理:
fetch
支持流式请求,而XHR
不支持。
fetch vs axios
- 库 vs API:
fetch
是浏览器内置 API,无需安装;axios
是第三方库,需要安装。 - 自动转换:
axios
会自动将 JSON 数据转换为 JavaScript 对象,而fetch
需要手动处理。 - 拦截器:
axios
支持请求和响应拦截器,fetch
不支持。 - 取消请求:
axios
支持取消请求,fetch
需要使用AbortController
。
优缺点分析
优点
- 基于 Promise:
fetch
使用 Promise 处理异步操作,使得代码更加简洁和易读。 - 更现代的语法:
fetch
的语法更加现代化,易于理解和使用。 - 流式处理:
fetch
支持流式请求和响应,适用于处理大文件或实时数据流。 - 内置跨域支持:
fetch
默认支持跨域请求(CORS),无需额外配置。 - 更好的错误处理:
fetch
只在网络错误时拒绝 Promise,HTTP 错误状态不会导致拒绝。
缺点
- 不支持旧版浏览器:
fetch
是一个较新的 API,不被所有浏览器支持。 - HTTP 错误处理复杂:
fetch
只在网络错误时拒绝 Promise,HTTP 错误状态需要手动处理。 - 不支持请求取消:
fetch
本身不支持请求取消,需要使用AbortController
。 - 不支持自动转换 JSON 数据:
fetch
不会自动将 JSON 数据转换为 JavaScript 对象。 - 不支持拦截器:
fetch
不支持请求和响应拦截器。
底层原理
基于 Promise
fetch
返回一个 Promise
,这使得异步操作的处理更加简洁和现代化。当请求完成时,Promise
会根据请求的结果(成功或失败)被解析为 Response
对象或拒绝。
基于 XMLHttpRequest
fetch
是基于浏览器的原生 XMLHttpRequest
对象(XHR)实现的。XHR 是一种传统的数据请求方式,而 fetch
API 则代表了现代 Web 开发的新兴标准。
实现细节
- 创建请求: 调用
fetch()
函数时,浏览器会创建一个新的XMLHttpRequest
对象来发起请求。 - 发送请求: 通过
XMLHttpRequest
对象的open()
和send()
方法发送请求。 - 处理响应: 请求完成后,
XMLHttpRequest
对象的onreadystatechange
事件会被触发,fetch
API 通过封装这个事件处理程序来处理响应。
流式处理的实现
流式处理是 fetch
的一个重要特性,它允许数据分块传输,适用于处理大文件或实时数据流。fetch
使用 ReadableStream
API 来实现流式处理。
fetch("https://api.example.com/large-data").then((response) => {
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
reader.read().then(function processText({ done, value }) {
if (done) {
console.log("Stream is complete");
return;
}
const chunk = decoder.decode(value, { stream: true });
console.log("Received chunk:", chunk);
return reader.read().then(processText);
});
});
在这个例子中,我们使用 fetch
发起一个 GET 请求,并处理返回的流式数据。
错误处理的实现
fetch
只在网络错误时拒绝 Promise,HTTP 错误状态(如 404)不会导致拒绝。开发者需要手动检查响应状态并进行相应处理。
fetch("https://api.example.com/data")
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
})
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));
在这个例子中,我们使用 fetch
发起一个 GET 请求,并处理返回的 JSON 数据。
请求取消的实现
fetch
本身不支持请求取消,需要使用 AbortController
来实现。
const controller = new AbortController();
const signal = controller.signal;
fetch("https://api.example.com/data", { signal })
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => {
if (error.name === "AbortError") {
console.log("Fetch aborted");
} else {
console.error("Error:", error);
}
});
// 取消请求
controller.abort();
在这个例子中,我们使用 fetch
发起一个 GET 请求,并演示了如何取消请求。
结论
fetch
API 提供了一种现代、简洁且强大的方式来处理网络请求。它的 Promise 基础和流式处理能力使其在许多场景下优于传统的 XHR
和第三方库 axios
。然而,开发者在使用 fetch
时需要注意其兼容性、错误处理和请求取消等方面的限制。
通过深入了解 fetch
请求的概念、使用方法和优缺点,开发者可以更好地选择合适的网络请求方式,提升前端开发的效率和性能。
叁考资料
希望本文能帮助你更好地理解和应用 fetch
请求。如果有任何问题或建议,欢迎在评论区留言!