在 JavaScript 中,Promise 是一种用于处理异步操作的对象,而 fetch 是现代浏览器提供的用于发起网络请求的 API,fetch API 本身返回的就是一个 Promise 对象,这使得我们可以优雅地处理网络请求的异步响应。
1. Promise 复习
Promise 有三种状态:
ending(进行中)
fulfilled(已成功)
rejected(已失败)
基本用法:
const promise = new Promise((resolve, reject) => {
// 异步操作代码
if (操作成功) {
resolve(结果);
} else {
reject(错误);
}
});
promise.then(结果 => {
// 处理成功情况
}).catch(错误 => {
// 处理失败情况
}).finally(() => {
// 无论成功失败都会执行
});2. fetch API 基础
fetch() 是一个全局方法,用于发起 HTTP 请求,返回一个 Promise 对象,该 Promise 会在请求响应后被解析。
基本语法:
fetch(url, options)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json(); // 解析JSON数据
})
.then(data => {
console.log(data); // 使用解析后的数据
})
.catch(error => {
console.error('Fetch error:', error);
});3. fetch 返回 Promise 的特性
fetch 返回的 Promise 在以下情况会被解析:
当接收到服务器响应时(即使响应状态码表示错误,如 404 或 500)。
只有当网络错误阻止请求完成时才会被拒绝(如断网)。
重要特性:fetch 的 Promise 不会因为 HTTP 错误状态码(如 404、500)而被拒绝,只有当网络请求本身失败时才会拒绝。因此,必须手动检查 response.ok 属性。
4. Promise 与 fetch 结合使用的高级场景
4.1 处理不同类型的响应
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
// 根据 Content-Type 决定如何解析响应
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return response.json();
} else if (contentType && contentType.includes('text/plain')) {
return response.text();
}
throw new Error('Unsupported content type');
})
.then(data => {
console.log('处理后的数据:', data);
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});4.2 使用 async/await 简化 fetch 代码
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
return data;
} catch (error) {
console.error('Fetch error:', error);
throw error; // 可以选择继续抛出以便上层处理
}
}
// 调用函数
fetchData().then(result => {
// 使用结果
}).catch(err => {
// 处理错误
});4.3 并行发起多个 fetch 请求
利用 Promise.all() 可以并行发起多个网络请求:
const fetchUser = fetch('https://api.example.com/user');
const fetchPosts = fetch('https://api.example.com/posts');
const fetchComments = fetch('https://api.example.com/comments');
Promise.all([fetchUser, fetchPosts, fetchComments])
.then(responses => {
// 确保所有响应都成功
const validResponses = responses.map(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
});
// 等待所有数据解析完成
return Promise.all(validResponses);
})
.then(([userData, postsData, commentsData]) => {
// 同时获取到了所有数据
console.log('用户数据:', userData);
console.log('帖子数据:', postsData);
console.log('评论数据:', commentsData);
})
.catch(error => {
console.error('至少一个请求失败:', error);
});5. fetch 的常见配置选项
fetch('https://api.example.com/data', {
method: 'POST', // GET, POST, PUT, DELETE 等
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token-here'
},
body: JSON.stringify({ key: 'value' }), // 仅用于 POST, PUT 等
credentials: 'include', // 包含 cookies
cache: 'no-cache',
redirect: 'follow',
referrerPolicy: 'no-referrer'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));6. 总结
Promise 是处理异步操作的基础,提供了一种优雅的方式来处理异步代码。
fetch 是基于 Promise 的网络请求 API,返回 Promise 对象。
fetch 的 Promise 仅在网络错误时拒绝,HTTP 错误状态码需要手动处理。
结合 async/await 可以使 fetch 代码更加简洁易读。
Promise.all() 等静态方法可以与 fetch 结合,实现并行请求等高级场景。
通过 Promise 和 fetch 的结合使用,我们可以编写更加清晰、可维护的异步网络请求代码。