Fetch是一种新的、基于promise的API,它允许我们在执行Ajax请求时不需要处理与XMLHttpRequest相关的所有麻烦。正如你将在这篇文章中看到的,Fetch非常容易使用,并且极大地简化了从API获取资源的过程。另外,所有的现代浏览器都支持它,因此Fetch使用起来非常简单。
Get请求
让我们通过从JSONPlaceholder API获取一些假数据来演示一个简单的GET请求:
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(res => res.map(user => user.username))
.then(userNames => console.log(userNames));
输出将是这样的用户名数组:
["Bret", "Antonette", "Samantha", "Karianne", "Kamren", "Leopoldo_Corkery", "Elwyn.Skiles", "Maxime_Nienow", "Delphine", "Moriah.Stanton"]
如果我们期望得到一个JSON响应,我们首先需要调用json()方法将Response对象转换为可以与之交互的对象。如果我们期望得到XML响应,则可以使用text()。
Post, Put 以及 Delete 请求
要发出除GET以外的请求,可以将一个对象作为第二个参数传递给fetch调用,这个对象还需要包含头文件和请求正文:
const myPost = {
title: 'A post about true facts',
body: '42',
userId: 2
}
const options = {
method: 'POST',
body: JSON.stringify(myPost),
headers: {
'Content-Type': 'application/json'
}
};
fetch('https://jsonplaceholder.typicode.com/posts', options)
.then(res => res.json())
.then(res => console.log(res));
JSONPlaceholder会将发送的数据连同ID一起返回给我们:
Object {
body: 42,
id: 101,
title: "A post about true facts",
userId: 2
}
你可能有注意到,这个请求的主体需要字符串化。另外一些可以使用的fetch的方法有DELETE
、PUT
、HEAD
和OPTIONS
。
错误处理
使用Fetch API处理错误时有一个陷阱(双关语😉):如果请求正确地到达端点并返回,则不会抛出任何错误。这意味着处理错误不能像在promise链的末尾链接catch
方法那么简单。
幸运的是,来自fetch调用返回的响应对象具有ok
属性,根据请求的成功情况,该属性将为true或false。当ok
为false的时候你可以使用Promise.reject()
:
fetch('https://jsonplaceholder.typicode.com/postsZZZ', options)
.then(res => {
if (res.ok) {
return res.json();
} else {
return Promise.reject({ status: res.status, statusText: res.statusText });
}
})
.then(res => console.log(res))
.catch(err => console.log('Error, with message:', err.statusText));
在上述示例中,我们的promise将被拒绝,因为我们正在调用不存在的端点。链接的catch将会被调用并输出以下内容:
"Error, with message: Not Found"
Fetch + Async/Await
由于Fetch是一个基于promise的API,使用异步函数是一个不错的选择,让你的代码更容易推理和同步查找。
例如,这里有一个async/await函数,它执行一个简单的GET请求,并从返回的JSON响应中提取用户名,然后在控制台输出结果:
async function fetchUsers(endpoint) {
const res = await fetch(endpoint);
let data = await res.json();
data = data.map(user => user.username);
console.log(data);
}
fetchUsers('https://jsonplaceholder.typicode.com/users');
或者,可以从你的异步/等待函数返回一个promise,然后你就可以保持链接,然后在调用该函数后进行调用:
async function fetchUsers(endpoint) {
const res = await fetch(endpoint);
const data = await res.json();
return data;
}
fetchUsers('https://jsonplaceholder.typicode.com/users')
.then(data => {
console.log(data.map(user => user.username));
});
调用json()
会返回一个promise,因此在上面的示例中,当我们在async函数中返回数据时,我们返回了一个promise。
然后,如果响应的ok
为false,那么你也可以抛出一个错误,并像往常一样在promise链中捕获错误:
async function fetchUsers(endpoint) {
const res = await fetch(endpoint);
if (!res.ok) {
throw new Error(res.status); // 404
}
const data = await res.json();
return data;
}
fetchUsers('https://jsonplaceholder.typicode.com/usersZZZ')
.then(data => {
console.log(data.map(user => user.website));
})
.catch(err => console.log('Ooops, error', err.message));
Ooops, error 404
Polyfills
如果你需要支持较旧的浏览器,例如Internet Explorer 11,则需要使用Github中的Fetch polyfill。
如果需要在Node.js中使用Fetch,则两个最受欢迎的选择是isomorphic-fetch和node-fetch。